Controlla se due elenchi collegati si uniscono. In caso affermativo, dove?


102

Questa domanda potrebbe essere vecchia, ma non riuscivo a trovare una risposta.

Diciamo, ci sono due elenchi di lunghezze diverse, che si fondono in un punto ; come sappiamo dov'è il punto di fusione?

Condizioni:

  1. Non sappiamo la lunghezza
  2. Dovremmo analizzare ogni elenco solo una volta.

Esempio di due elenchi collegati uniti.


unire significa che da quel punto ci sarà solo una lista.
rplusg

è consentita la modifica della lista?
Artelius

1
Sono abbastanza sicuro che non funzioni senza la modifica dell'elenco. (O semplicemente copiandolo da qualche altra parte per evitare la restrizione di analizzarlo solo una volta.)
Georg Schölly,

2
Potrebbe essere stato il punto. Dannati intervistatori! Hehe
Kyle Rosendo

1
Ho una proposta interessante ... supponendo che la coda comune della lista sia infinitamente lunga. Come puoi trovare l'intersezione dei nodi usando la memoria costante?
Akusete

Risposte:


36

Se

  • con "la modifica non è consentita" si intendeva "puoi cambiare ma alla fine dovrebbero essere ripristinati", e
  • potremmo iterare gli elenchi esattamente due volte

il seguente algoritmo sarebbe la soluzione.

Primo, i numeri. Supponiamo che la prima lista sia di lunghezza a+ce la seconda sia di lunghezza b+c, dove cè la lunghezza della loro "coda" comune (dopo il punto di unione). Indichiamoli come segue:

x = a+c
y = b+c

Poiché non conosciamo la lunghezza, la calcoleremo xe ysenza iterazioni aggiuntive; vedrai come.

Quindi, iteriamo ogni elenco e li invertiamo durante l'iterazione! Se entrambi gli iteratori raggiungono il punto di fusione contemporaneamente, lo scopriamo semplicemente confrontando. Altrimenti, un puntatore raggiungerà il punto di unione prima dell'altro.

Dopodiché, quando l'altro iteratore raggiunge il punto di unione, non procederà alla coda comune. Invece tornerà al precedente inizio della lista che aveva raggiunto il punto di unione prima! Quindi, prima che raggiunga la fine della lista modificata (cioè l'inizio precedente dell'altra lista), farà il a+b+1totale delle iterazioni. Chiamiamolo z+1.

Il puntatore che ha raggiunto per primo il punto di unione, continuerà a scorrere fino a raggiungere la fine dell'elenco. Il numero di iterazioni che ha fatto dovrebbe essere calcolato ed è uguale a x.

Quindi, questo puntatore torna indietro e inverte nuovamente gli elenchi. Ma ora non tornerà all'inizio dell'elenco da cui originariamente era partito! Invece, andrà all'inizio dell'altro elenco! Il numero di iterazioni che ha fatto dovrebbe essere calcolato e uguale a y.

Quindi conosciamo i seguenti numeri:

x = a+c
y = b+c
z = a+b

Da cui lo determiniamo

a = (+x-y+z)/2
b = (-x+y+z)/2
c = (+x+y-z)/2

Che risolve il problema.


2
Commento agli stati della domanda modifica della lista non consentita!
Skizz

1
Mi piace questa risposta (molto creativa). L'unico problema che ho con esso è che presume che tu conosca la lunghezza di entrambe le liste.
tster

non puoi modificare l'elenco e non sappiamo la lunghezza - questi sono i vincoli ... comunque, grazie per una risposta creativa.
rplusg

2
@tster, @calvin, la risposta non presuppone, abbiamo bisogno della lunghezza. Può essere calcolato in linea. Aggiungendo spiegazioni alle mie risposte.
P Shved

2
@Forethinker l'hashing dei nodi visitati e / o contrassegnarli come visti richiede una memoria O (lunghezza della lista), mentre molte soluzioni (inclusa la mia, per quanto imperfetta e complicata sia) richiedono una memoria O (1).
P Shved

156

Quello che segue è di gran lunga il più grande di tutto quello che ho visto - O (N), nessun contatore. L'ho ricevuto durante un'intervista a un candidato SN a VisionMap .

Crea un puntatore interattivo come questo: va avanti ogni volta fino alla fine, quindi salta all'inizio dell'elenco opposto e così via. Crea due di questi, indicando due teste. Avanza ogni volta di 1 ogni indicatore finché non si incontrano. Questo accadrà dopo uno o due passaggi.

Uso ancora questa domanda nelle interviste, ma per vedere quanto tempo impiega qualcuno a capire perché questa soluzione funziona.


6
è semplicemente geniale!
Cong Hui

2
Questa è una buona risposta, ma devi scorrere gli elenchi due volte, il che viola la condizione 2.
tster

2
Trovo questa soluzione piuttosto elegante, se è garantita la presenza di un punto di unione. Non funzionerà per rilevare i punti di unione, poiché se uno non è presente, verrà ripetuto all'infinito.
direzione alternata

4
È super geniale! Spiegazione: abbiamo 2 liste: a-b-c-x-y-ze p-q-x-y-z. percorso del primo puntatore a,b,c,x,y,z,p,q,x, percorso del secondo puntatorep,q,x,y,z,a,b,c,x
Nikolai Golub

14
Brillante. Per coloro che non hanno capito, conta il numero di nodi percorsi da head1-> tail1 -> head2 -> punto di intersezione e head2 -> tail2-> head1 -> punto di intersezione. Entrambi saranno uguali (disegna tipi diff di elenchi collegati per verificarlo). Il motivo è che entrambi i puntatori devono percorrere le stesse distanze head1-> IP + head2-> IP prima di raggiungere nuovamente l'IP. Quindi, quando raggiunge l'IP, entrambi i puntatori saranno uguali e avremo il punto di fusione.
adev

91

La risposta di Pavel richiede la modifica delle liste e l' iterazione di ciascuna lista due volte.

Ecco una soluzione che richiede solo di iterare ogni elenco due volte (la prima volta per calcolare la loro lunghezza; se la lunghezza è data, devi solo iterare una volta).

L'idea è di ignorare le voci iniziali dell'elenco più lungo (il punto di unione non può essere lì), in modo che i due puntatori siano alla stessa distanza dalla fine dell'elenco. Quindi spostali in avanti finché non si uniscono.

lenA = count(listA) //iterates list A
lenB = count(listB) //iterates list B

ptrA = listA
ptrB = listB

//now we adjust either ptrA or ptrB so that they are equally far from the end
while(lenA > lenB):
    ptrA = ptrA->next
    lenA--
while(lenB > lenA):
    prtB = ptrB->next
    lenB--

while(ptrA != NULL):
    if (ptrA == ptrB):
        return ptrA //found merge point
    ptrA = ptrA->next
    ptrB = ptrB->next

Questo è asintoticamente lo stesso (tempo lineare) della mia altra risposta ma probabilmente ha costanti più piccole, quindi è probabilmente più veloce. Ma penso che la mia altra risposta sia più interessante.


4
Oggi, mentre stavamo bevendo vodka, ho proposto questa domanda a un mio amico, che ha dato via la tua stessa risposta e ha chiesto di postarla su SO. Ma sembri essere il primo. Quindi farò un +1 per te da me e vorrei poter fare un altro +1.
P Shved

2
+1 come questo e inoltre non necessita di alcuna modifica all'elenco, inoltre la maggior parte delle implementazioni dell'elenco collegato di solito prevede la lunghezza
keshav84

3
Abbiamo troppi Pavel. La mia soluzione non richiede la modifica dell'elenco.
Pavel Radzivilovsky

Buona risposta. Quale sarà la complessità temporale per questo però. 0 (n + m)? dove n = nodi nell'elenco 1, m = nodi nell'elenco 2?
Vihaan Verma

invece di spostare entrambi i puntatori in entrambe le liste: possiamo solo vedere se diff> = small of two path, se sì, quindi spostarsi in una piccola lista di un valore piccolo altrimenti spostarsi in una piccola lista di diff + 1 value; se diff è 0, l'ultimo nodo è la risposta.
Vishal Anand

30

Bene, se sai che si uniranno:

Supponi di iniziare con:

A-->B-->C
        |
        V
1-->2-->3-->4-->5

1) Scorri il primo elenco impostando ogni puntatore successivo su NULL.

Adesso hai:

A   B   C

1-->2-->3   4   5

2) Ora scorri il secondo elenco e attendi fino a quando non vedi un NULL, che è il tuo punto di unione.

Se non puoi essere sicuro che si uniscano, puoi usare un valore sentinella per il valore del puntatore, ma non è così elegante.


3
Tuttavia, distruggi l'elenco nel processo, per non essere mai più utilizzato: P
Kyle Rosendo,

@ Kyle Rozendo, beh, la mia soluzione cambia gli elenchi nel modo in cui possono essere ripristinati dopo l'elaborazione. Ma questa è una dimostrazione più chiara del concetto
P Shved il

Non ho visto che la modifica dell'elenco non era consentita. Ci penso, ma non mi viene in mente nulla senza memorizzare ogni nodo visto.
tster

10
Dai, questa è la risposta corretta! Dobbiamo solo aggiustare la domanda :)
P Shved il

23
Ottimo algoritmo per creare perdite di memoria.
Karoly Horvath

14

Se potessimo iterare gli elenchi esattamente due volte, posso fornire un metodo per determinare il punto di unione:

  • itera entrambe le liste e calcola le lunghezze A e B
  • calcolare la differenza di lunghezze C = | AB |;
  • inizia a iterare entrambe le liste contemporaneamente, ma esegui ulteriori passaggi C sulla lista che era maggiore
  • questi due puntatori si incontreranno nel punto di fusione

8

Ecco una soluzione, computazionalmente veloce (itera ogni elenco una volta) ma utilizza molta memoria:

for each item in list a
  push pointer to item onto stack_a

for each item in list b
  push pointer to item onto stack_b

while (stack_a top == stack_b top) // where top is the item to be popped next
  pop stack_a
  pop stack_b

// values at the top of each stack are the items prior to the merged item

2
È l'equivalente di elaborare una lista due volte.
Georg Schölly,

Suppongo che, tecnicamente, tu stia facendo cose con le liste due volte, ma è un miglioramento significativo rispetto alla soluzione di Kyle Rozendo. Ora, se "elaborare l'elenco" è definito come "leggere il valore del collegamento e seguire il puntatore", si potrebbe sostenere che elabora l'elenco una volta: legge ogni valore di collegamento una volta, lo memorizza e quindi li confronta.
Skizz

Sarà sicuramente più veloce del mio, senza dubbio.
Kyle Rosendo

7

Puoi usare un insieme di nodi. Scorri un elenco e aggiungi ogni nodo al set. Quindi itera attraverso il secondo elenco e per ogni iterazione, controlla se il nodo esiste nell'insieme. Se è così, hai trovato il tuo punto di unione :)


Temo (a causa di Ω (n) spazio aggiuntivo) questo è l'unico approccio (non una sorta di ricostruzione delle liste e) non analizzare una lista più di una volta. Il rilevamento di un loop nell'elenco è banale per il primo elenco (controlla se il nodo è impostato): utilizza qualsiasi metodo di rilevamento del loop sul secondo elenco per garantire la terminazione. (La domanda dell'intervista potrebbe riguardare l'ascolto attento di una dichiarazione di problema e il non saltare per usare un martello che sai per colpire qualcosa che non è proprio un chiodo.)
Barba grigia

6

Ciò probabilmente viola la condizione "analizza ogni elenco solo una volta", ma implementa l' algoritmo tartaruga e lepre (usato per trovare il punto di unione e la lunghezza del ciclo di un elenco ciclico) in modo da iniziare dall'elenco A e quando si raggiunge il NULL al alla fine fingi che sia un puntatore all'inizio dell'elenco B, creando così l'aspetto di un elenco ciclico. L'algoritmo ti dirà quindi esattamente quanto è in fondo alla lista A l'unione (la variabile 'mu' secondo la descrizione di Wikipedia).

Inoltre, il valore "lambda" ti dice la lunghezza della lista B e, se vuoi, puoi calcolare la lunghezza della lista A durante l'algoritmo (quando reindirizzi il collegamento NULL).


Più o meno quello che ho detto, solo con nomi più elaborati. : P
Kyle Rosendo,

Affatto. Questa soluzione è O (n) nelle operazioni e O (1) nell'utilizzo della memoria (infatti richiede solo due variabili puntatore).
Artelius

Sì, avrei dovuto cancellare il mio commento precedente poiché la mia soluzione è cambiata un po '. Hehe.
Kyle Rosendo,

Ma non vedo come fosse applicabile in primo luogo?
Artelius

La tua spiegazione sì, non l'algoritmo stesso. Forse la vedo diversamente, ma ehi.
Kyle Rosendo,

3

Forse sto semplificando troppo, ma semplicemente iterare l'elenco più piccolo e utilizzare gli ultimi nodi Linkcome punto di fusione?

Allora, dov'è Data->Link->Link == NULLil punto finale, dando Data->Linkcome punto di fusione (alla fine della lista).

MODIFICARE:

Ok, dalla foto che hai postato, analizzi i due elenchi, il più piccolo per primo. Con l'elenco più piccolo è possibile mantenere i riferimenti al nodo successivo. Ora, quando analizzi la seconda lista, fai un confronto sul riferimento per trovare dove Riferimento [i] è il riferimento su LinkedList [i] -> Link. Questo darà il punto di unione. È ora di spiegare con le immagini (sovrapporre i valori sull'immagine l'OP).

Hai un elenco collegato (riferimenti mostrati di seguito):

A->B->C->D->E

Hai una seconda lista collegata:

1->2->

Con l'elenco unito, i riferimenti sarebbero quindi i seguenti:

1->2->D->E->

Pertanto, mappi il primo elenco "più piccolo" (poiché l'elenco unito, che è quello che stiamo contando ha una lunghezza di 4 e l'elenco principale di 5)

Scorri il primo elenco, mantieni un riferimento di riferimenti.

L'elenco conterrà i seguenti riferimenti Pointers { 1, 2, D, E }.

Passiamo ora al secondo elenco:

-> A - Contains reference in Pointers? No, move on
-> B - Contains reference in Pointers? No, move on
-> C - Contains reference in Pointers? No, move on
-> D - Contains reference in Pointers? Yes, merge point found, break.

Certo, mantieni un nuovo elenco di puntatori, ma non è al di fuori delle specifiche. Tuttavia, il primo elenco viene analizzato esattamente una volta e il secondo elenco verrà analizzato completamente solo se non esiste un punto di unione. Altrimenti, finirà prima (al punto di unione).


Bene cambia leggermente da quello che volevo dire all'inizio, ma da quello che sembra volere l'OP, questo farà il trucco.
Kyle Rosendo,

Adesso è più chiaro. Ma lineare nell'uso della memoria. Non mi piace.
Artelius

La domanda non chiedeva di più, altrimenti l'intero processo può essere multithread. Questa è ancora una visione semplicistica "di primo livello" della soluzione, il codice può essere implementato in diversi modi. :)
Kyle Rosendo

1
Uh, cosa? Il multithreading è un modo per utilizzare meglio la potenza di elaborazione, non riducendo la potenza di elaborazione totale richiesta da un algoritmo. E dire che il codice può essere implementato in molti modi è solo una scusa.
Artelius

1
Questo piega davvero "analizzare ogni elenco solo una volta" fino al punto di rottura. Tutto quello che stai facendo è copiare un elenco e quindi controllare l'altro elenco rispetto alla copia.
Skizz

3

Ho testato un caso di unione sul mio FC9 x86_64 e ho stampato ogni indirizzo di nodo come mostrato di seguito:

Head A 0x7fffb2f3c4b0
0x214f010
0x214f030
0x214f050
0x214f070
0x214f090
0x214f0f0
0x214f110
0x214f130
0x214f150
0x214f170


Head B 0x7fffb2f3c4a0
0x214f0b0
0x214f0d0
0x214f0f0
0x214f110
0x214f130
0x214f150
0x214f170

Nota perché avevo allineato la struttura del nodo, quindi quando malloc () un nodo, l'indirizzo è allineato con 16 byte, vedi almeno 4 bit. I bit minimi sono 0, ovvero 0x0 o 000b. Quindi, se anche tu sei nello stesso caso speciale (indirizzo di nodo allineato), puoi usare questi almeno 4 bit. Ad esempio, quando si spostano entrambe le liste dalla testa alla coda, impostare 1 o 2 dei 4 bit dell'indirizzo del nodo in visita, ovvero impostare un flag;

next_node = node->next;
node = (struct node*)((unsigned long)node | 0x1UL);

Nota i flag sopra non influenzeranno l'indirizzo del nodo reale ma solo il valore del puntatore del nodo SALVATO.

Una volta trovato qualcuno che ha impostato i bit flag, il primo nodo trovato dovrebbe essere il punto di unione. al termine, ripristinerai l'indirizzo del nodo cancellando i bit di flag che avevi impostato. mentre una cosa importante è che dovresti stare attento quando iterare (ad esempio node = node-> next) per pulire. ricorda di aver impostato i bit flag, quindi fai in questo modo

real_node = (struct node*)((unsigned long)node) & ~0x1UL);
real_node = real_node->next;
node = real_node;

Poiché questa proposta ripristinerà gli indirizzi di nodo modificati, potrebbe essere considerata come "nessuna modifica".


+1, questo è ciò che viene in mente naturalmente con "iterate solo una volta" non so perché questo non si è mai alzato votato! Bella soluzione.
jman

3

Può esserci una soluzione semplice ma richiederà uno spazio ausiliario. L'idea è di attraversare un elenco e memorizzare ogni indirizzo in una mappa hash, ora attraversare l'altro elenco e abbinare se l'indirizzo si trova nella mappa hash o meno. Ciascun elenco viene esaminato una sola volta. Non ci sono modifiche a nessun elenco. La lunghezza è ancora sconosciuta. Spazio ausiliario utilizzato: O (n) dove 'n' è la lunghezza del primo elenco attraversato.


2

questa soluzione itera ogni lista solo una volta ... non è richiesta anche alcuna modifica della lista .. anche se potresti lamentarti dello spazio ..
1) Fondamentalmente si itera in list1 e si memorizza l'indirizzo di ogni nodo in un array (che memorizza il valore int senza segno)
2) Quindi iterate list2 e per l'indirizzo di ogni nodo ---> cercate nell'array che trovate una corrispondenza o meno ... se lo fate allora questo è il nodo che si unisce

//pseudocode
//for the first list
p1=list1;
unsigned int addr[];//to store addresses
i=0;
while(p1!=null){
  addr[i]=&p1;
  p1=p1->next;
}
int len=sizeof(addr)/sizeof(int);//calculates length of array addr
//for the second list
p2=list2;
while(p2!=null){
  if(search(addr[],len,&p2)==1)//match found
  {
    //this is the merging node
    return (p2);
  }
  p2=p2->next;
}

int search(addr,len,p2){
  i=0;  
  while(i<len){
    if(addr[i]==p2)
      return 1;
    i++;
  }
 return 0;
} 

Spero sia una soluzione valida ...


Questo praticamente itera uno degli elenchi più di una volta, sebbene sotto forma di un array invece dell'elenco stesso.
syockit

1

Non è necessario modificare alcun elenco. C'è una soluzione in cui dobbiamo solo attraversare ogni lista una volta.

  1. Crea due stack, diciamo stck1 e stck2.
  2. Attraversa il primo elenco e invia una copia di ogni nodo che attraversi in stck1.
  3. Come il passaggio due, ma questa volta attraversa il 2 ° elenco e invia la copia dei nodi in stck2.
  4. Ora, fai un salto da entrambi gli stack e controlla se i due nodi sono uguali, se sì, mantieni un riferimento a loro. In caso contrario, i nodi precedenti che erano uguali sono in realtà il punto di unione che stavamo cercando.

1
int FindMergeNode(Node headA, Node headB) {
  Node currentA = headA;
  Node currentB = headB;

  // Do till the two nodes are the same
  while (currentA != currentB) {
    // If you reached the end of one list start at the beginning of the other
    // one currentA
    if (currentA.next == null) {
      currentA = headA;
    } else {
      currentA = currentA.next;
    }
    // currentB
    if (currentB.next == null) {
      currentB = headB;
    } else {
      currentB = currentB.next;
    }
  }
  return currentB.data;
}

Nella sua revisione originale, questo indicava solo la risposta più votata (Pavel Radzivilovsky, 2013) .
barba grigia il

0

Ecco una soluzione ingenua, non c'è bisogno di attraversare intere liste.

se il tuo nodo strutturato ha tre campi come

struct node {
    int data;   
    int flag;  //initially set the flag to zero  for all nodes
    struct node *next;
};

diciamo che hai due teste (head1 e head2) che puntano all'inizio di due liste.

Attraversa entrambe le liste allo stesso ritmo e metti la bandiera = 1 (bandiera visitata) per quel nodo,

  if (node->next->field==1)//possibly longer list will have this opportunity
      //this will be your required node. 

0

Cosa ne pensi di questo:

  1. Se puoi attraversare ogni elenco solo una volta, puoi creare un nuovo nodo, attraversare il primo elenco per fare in modo che ogni nodo punti a questo nuovo nodo e attraversare il secondo elenco per vedere se qualche nodo punta al tuo nuovo nodo ( questo è il tuo punto di unione). Se il secondo attraversamento non porta al tuo nuovo nodo, gli elenchi originali non hanno un punto di unione.

  2. Se ti è permesso di attraversare le liste più di una volta, puoi attraversare ciascuna lista per trovare la nostra lunghezza e se sono diverse, ometti i nodi "extra" all'inizio della lista più lunga. Quindi attraversa entrambi gli elenchi un passaggio alla volta e trova il primo nodo di fusione.


1. non solo modifica ma distrugge il primo elenco. 2. è suggerito più volte.
barba grigia

0

Passaggi in Java:

  1. Crea una mappa.
  2. Inizia ad attraversare in entrambi i rami della lista e Metti tutti i nodi attraversati della lista nella mappa usando qualcosa di univoco correlato ai nodi (diciamo ID nodo) come chiave e metti Valori come 1 all'inizio per tutti.
  3. Quando arriva la prima chiave duplicata, incrementa il valore per quella chiave (diciamo ora che il suo valore è diventato 2 che è> 1.
  4. Ottieni la chiave in cui il valore è maggiore di 1 e dovrebbe essere il nodo in cui si stanno unendo due elenchi.

1
E se avessimo ciclo nella parte unita?
Rohit

Ma per i cicli di gestione degli errori, questa assomiglia molto alla risposta di isyi .
barba grigia

0

Possiamo risolverlo efficacemente introducendo il campo "isVisited". Attraversa il primo elenco e imposta il valore "isVisited" su "true" per tutti i nodi fino alla fine. Ora inizia dal secondo e trova il primo nodo in cui flag è true e Boom, è il tuo punto di fusione.


0

Passaggio 1: trova la lunghezza di entrambi gli elenchi Passaggio 2: Trova il diff e sposta l'elenco più grande con la differenza Passaggio 3: Ora entrambi gli elenchi saranno in una posizione simile. Passaggio 4: scorrere l'elenco per trovare il punto di unione

//Psuedocode
def findmergepoint(list1, list2):
lendiff = list1.length() > list2.length() : list1.length() - list2.length() ? list2.lenght()-list1.lenght()
biggerlist = list1.length() > list2.length() : list1 ? list2  # list with biggest length
smallerlist = list1.length() < list2.length() : list2 ? list1 # list with smallest length


# move the biggest length to the diff position to level both the list at the same position
for i in range(0,lendiff-1):
    biggerlist = biggerlist.next
#Looped only once.  
while ( biggerlist is not None and smallerlist is not None ):
    if biggerlist == smallerlist :
        return biggerlist #point of intersection


return None // No intersection found

(Mi è piaciuto di più l'elenco con ogni elemento che inizia una riga. Considera l'idea di utilizzare un correttore ortografico.)
greybeard

0
int FindMergeNode(Node *headA, Node *headB)
{
    Node *tempB=new Node;
    tempB=headB;
   while(headA->next!=NULL)
       {
       while(tempB->next!=NULL)
           {
           if(tempB==headA)
               return tempB->data;
           tempB=tempB->next;
       }
       headA=headA->next;
       tempB=headB;
   }
    return headA->data;
}

Devi aggiungere qualche spiegazione alla tua risposta. Solo le risposte in codice possono essere eliminate.
rghome

0

Usa mappa o dizionario per memorizzare il valore degli indirizzi rispetto al nodo. se l'indirizzo già letto esiste nella mappa / dizionario, il valore della chiave è la risposta. L'ho fatto:

int FindMergeNode(Node headA, Node headB) {

Map<Object, Integer> map = new HashMap<Object, Integer>();

while(headA != null || headB != null)
{
    if(headA != null && map.containsKey(headA.next))
    {
        return map.get(headA.next);
    }

    if(headA != null && headA.next != null)
    {
         map.put(headA.next, headA.next.data);
         headA = headA.next;
    }

    if(headB != null && map.containsKey(headB.next))
    {
        return map.get(headB.next);
    }

    if(headB != null && headB.next != null)
    {
        map.put(headB.next, headB.next.data);
        headB = headB.next;
    }
}

return 0;
}

0

Soluzione di complessità AO (n). Ma basato su un'ipotesi.

l'ipotesi è: entrambi i nodi hanno solo numeri interi positivi.

logica: rende negativo tutto il numero intero di lista1. Quindi esplora list2, finché non ottieni un numero intero negativo. Una volta trovato => prendilo, cambia il segno di nuovo in positivo e torna.

static int findMergeNode(SinglyLinkedListNode head1, SinglyLinkedListNode head2) {

    SinglyLinkedListNode current = head1; //head1 is give to be not null.

    //mark all head1 nodes as negative
    while(true){
        current.data = -current.data;
        current = current.next;
        if(current==null) break;
    }

    current=head2; //given as not null
    while(true){
        if(current.data<0) return -current.data;
        current = current.next;
    }

}

0

Possiamo usare due puntatori e muoverci in modo tale che se uno dei puntatori è nullo lo indichiamo all'inizio dell'altra lista e lo stesso per l'altra, in questo modo se le lunghezze della lista sono diverse si incontreranno nel secondo passaggio . Se la lunghezza di lista1 è n e lista2 è m, la loro differenza è d = abs (nm). Copriranno questa distanza e si incontreranno nel punto di unione.
Codice:

int findMergeNode(SinglyLinkedListNode* head1, SinglyLinkedListNode* head2) {
    SinglyLinkedListNode* start1=head1;
    SinglyLinkedListNode* start2=head2;
    while (start1!=start2){
        start1=start1->next;
        start2=start2->next;
        if (!start1)
        start1=head2;
        if (!start2)
        start2=head1;
    }
    return start1->data;
}

0

Puoi aggiungere i nodi di list1a un hashset e il ciclo attraverso il secondo e se un qualsiasi nodo di list2è già presente nel set. Se sì, allora quello è il nodo di unione

static int findMergeNode(SinglyLinkedListNode head1, SinglyLinkedListNode head2) {
    HashSet<SinglyLinkedListNode> set=new HashSet<SinglyLinkedListNode>();
    while(head1!=null)
    {
        set.add(head1);
        head1=head1.next;
    }
    while(head2!=null){
        if(set.contains(head2){
            return head2.data;
        }
    }
    return -1;
}

0

Soluzione utilizzando javascript

var getIntersectionNode = function(headA, headB) {
    
    if(headA == null || headB == null) return null;
    
    let countA = listCount(headA);
    let countB = listCount(headB);
    
    let diff = 0;
    if(countA > countB) {

        diff = countA - countB;
        for(let i = 0; i < diff; i++) {
            headA = headA.next;
        }
    } else if(countA < countB) {
        diff = countB - countA;
        for(let i = 0; i < diff; i++) {
            headB = headB.next;
        }
    }

    return getIntersectValue(headA, headB);
};

function listCount(head) {
    let count = 0;
    while(head) {
        count++;
        head = head.next;
    }
    return count;
}

function getIntersectValue(headA, headB) {
    while(headA && headB) {
        if(headA === headB) {
            return headA;
        }
        headA = headA.next;
        headB = headB.next;
    }
    return null;
}

0

Se è consentita la modifica dell'elenco collegato,

  1. Quindi rendi nulli i puntatori del nodo successivo di tutti i nodi della lista 2.
  2. Trova il valore dei dati dell'ultimo nodo della lista 1. Questo ti darà il nodo intersecante in un singolo attraversamento di entrambe le liste, senza "logica hi fi".
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.