Vérifiez si deux listes liées fusionnent. Si oui, où?


102

Cette question est peut-être ancienne, mais je n'ai pas trouvé de réponse.

Disons qu'il existe deux listes de longueurs différentes, fusionnant en un point ; comment savoir où se situe le point de fusion?

Conditions:

  1. Nous ne connaissons pas la longueur
  2. Nous ne devrions analyser chaque liste qu'une seule fois.

Exemple de deux listes chaînées fusionnées.


fusionner signifie qu'à partir de là, il n'y aura qu'une seule liste.
rplusg

la modification de la liste est-elle autorisée?
Artelius

1
Je suis presque sûr que cela ne fonctionne pas sans modification de la liste. (Ou simplement le copier ailleurs pour éviter la restriction de l'analyser une seule fois.)
Georg Schölly

2
Cela aurait pu être le point. Damn interviewers! Hehe
Kyle Rosendo

1
J'ai une proposition intéressante ... en supposant que la queue commune de la liste soit infiniment longue. Comment pouvez-vous trouver l'intersection des nœuds en utilisant la mémoire constante?
Akusete

Réponses:


36

Si

  • par "la modification n'est pas autorisée", cela signifiait "vous pouvez changer mais à la fin ils devraient être restaurés", et
  • nous pourrions itérer les listes exactement deux fois

l'algorithme suivant serait la solution.

Premièrement, les chiffres. Supposons que la première liste est de longueur a+cet la seconde est de longueur b+c, où cest la longueur de leur "queue" commune (après le point de fusion). Notons-les comme suit:

x = a+c
y = b+c

Puisque nous ne connaissons pas la longueur, nous allons calculer xet ysans itérations supplémentaires; vous verrez comment.

Ensuite, nous itérons chaque liste et les inversons en itérant! Si les deux itérateurs atteignent le point de fusion en même temps, nous le découvrons par simple comparaison. Sinon, un pointeur atteindra le point de fusion avant l'autre.

Après cela, lorsque l'autre itérateur atteint le point de fusion, il ne passe pas à la queue commune. Au lieu de cela, reviendra à l'ancien début de la liste qui avait atteint le point de fusion auparavant! Ainsi, avant qu'il n'atteigne la fin de la liste modifiée (c'est-à-dire l'ancien début de l'autre liste), il fera le a+b+1total des itérations. Appelons ça z+1.

Le pointeur qui a atteint le point de fusion en premier continuera d'itérer jusqu'à ce qu'il atteigne la fin de la liste. Le nombre d'itérations effectuées doit être calculé et est égal à x.

Ensuite, ce pointeur effectue une itération en arrière et inverse à nouveau les listes. Mais maintenant, il ne retournera pas au début de la liste à partir de laquelle il a commencé! Au lieu de cela, il ira au début de l'autre liste! Le nombre d'itérations effectuées doit être calculé et égal à y.

Nous connaissons donc les chiffres suivants:

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

À partir de laquelle nous déterminons que

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

Ce qui résout le problème.


2
Le commentaire à la question indique que la modification de la liste n'est pas autorisée!
Skizz

1
J'aime cette réponse (très créative). Le seul problème que j'ai avec cela est qu'il suppose que vous connaissez la longueur des deux listes.
tster

vous ne pouvez pas modifier la liste, et nous ne connaissons pas la longueur - ce sont les contraintes ... de toute façon, merci pour une réponse créative.
rplusg

2
@tster, @calvin, la réponse ne suppose pas, nous avons besoin de la longueur. Il peut être calculé en ligne. Ajout d'explications à mes réponses.
P Shved

2
@Forethinker hacher les nœuds visités et / ou les marquer comme vus nécessite une mémoire O (longueur de la liste), tandis que de nombreuses solutions (y compris la mienne, aussi imparfaite et compliquée qu'elle soit) nécessitent de la mémoire O (1).
P Shved le

156

Ce qui suit est de loin le plus grand de tout ce que j'ai vu - O (N), pas de compteurs. Je l'ai eu lors d'un entretien avec un candidat SN chez VisionMap .

Créez un pointeur interactif comme celui-ci: il avance à chaque fois jusqu'à la fin, puis saute au début de la liste opposée, et ainsi de suite. Créez-en deux en indiquant deux têtes. Avancez chacun des pointeurs de 1 à chaque fois, jusqu'à ce qu'ils se rencontrent. Cela se produira après un ou deux passages.

J'utilise toujours cette question dans les entretiens - mais pour voir combien de temps il faut à quelqu'un pour comprendre pourquoi cette solution fonctionne.


6
c'est tout simplement génial!
Cong Hui

2
C'est une bonne réponse, mais vous devez parcourir les listes deux fois, ce qui enfreint la condition n ° 2.
tster

2
Je trouve cette solution assez élégante, si un point de fusion est assuré d'être présent. Cela ne fonctionnera pas pour détecter les points de fusion, car si l'un d'entre eux n'était pas présent, il bouclera indéfiniment.
direction alternée

4
C'est super génial! Explication: nous avons 2 listes: a-b-c-x-y-zet p-q-x-y-z. chemin du premier pointeur a,b,c,x,y,z,p,q,x, chemin du deuxième pointeurp,q,x,y,z,a,b,c,x
Nikolai Golub

14
Brillant. Pour ceux qui n'ont pas compris, comptez le nombre de nœuds parcourus depuis head1-> tail1 -> head2 -> point d'intersection et head2 -> tail2-> head1 -> intersection point. Les deux seront égaux (dessinez différents types de listes liées pour vérifier cela). La raison est que les deux pointeurs doivent parcourir les mêmes distances head1-> IP + head2-> IP avant d'atteindre à nouveau IP. Ainsi, au moment où il atteindra IP, les deux pointeurs seront égaux et nous aurons le point de fusion.
adev

91

La réponse de Pavel nécessite la modification des listes ainsi que l' itération de chaque liste deux fois.

Voici une solution qui ne nécessite d'itérer chaque liste que deux fois (la première fois pour calculer leur longueur; si la longueur est donnée, vous n'avez besoin d'itérer qu'une seule fois).

L'idée est d'ignorer les entrées de départ de la liste plus longue (le point de fusion ne peut pas être là), de sorte que les deux pointeurs soient à égale distance de la fin de la liste. Puis déplacez-les vers l'avant jusqu'à ce qu'ils fusionnent.

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

C'est asymptotiquement le même (temps linéaire) que mon autre réponse mais a probablement des constantes plus petites, donc probablement plus rapide. Mais je pense que mon autre réponse est plus cool.


4
Aujourd'hui, alors que nous buvions de la vodka, j'ai proposé cette question à un de mes amis, et il a donné la même réponse que la vôtre et a demandé à la poster sur SO. Mais vous semblez être le premier. Je vais donc faire un +1 pour vous de ma part et j'aimerais pouvoir faire un autre +1.
P Shved

2
+1 comme celui-ci et n'a pas besoin de modification de la liste, la plupart des implémentations de liste chaînée fournissent généralement de la longueur
keshav84

3
Nous avons trop de Pavels. Ma solution ne nécessite pas de modifier la liste.
Pavel Radzivilovsky

Bonne réponse. Quelle sera la complexité du temps pour cela cependant. 0 (n + m)? où n = nœuds dans la liste 1, m = nœuds dans la liste 2?
Vihaan Verma

au lieu de déplacer les deux pointeurs dans les deux listes: on peut juste voir si le diff> = petit de deux chemin, si oui, alors se déplacer dans une petite liste par petite valeur sinon se déplacer dans une petite liste par diff + 1 valeur; si diff est 0 alors le dernier nœud est la réponse.
Vishal Anand

30

Eh bien, si vous savez qu'ils fusionneront:

Disons que vous commencez par:

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

1) Parcourez la première liste en définissant chaque pointeur suivant sur NULL.

Maintenant vous avez:

A   B   C

1-->2-->3   4   5

2) Maintenant, parcourez la deuxième liste et attendez de voir un NULL, c'est votre point de fusion.

Si vous ne pouvez pas être sûr qu'ils fusionnent, vous pouvez utiliser une valeur sentinelle pour la valeur du pointeur, mais ce n'est pas aussi élégant.


3
Cependant, vous détruisez la liste dans le processus, pour ne plus jamais être utilisée: P
Kyle Rosendo

@Kyle Rozendo, eh bien, ma solution change les listes de la manière dont elles peuvent être restaurées après le traitement. Mais c'est une démonstration plus claire du concept
P Shved

Je n'ai pas vu que la modification de la liste n'était pas autorisée. Je vais y réfléchir, mais rien ne me vient à l'esprit sans stocker chaque nœud vu.
tster

10
Allez, c'est la bonne réponse! Nous devons juste ajuster la question :)
P Shved

23
Excellent algorithme pour créer des fuites de mémoire.
Karoly Horvath

14

Si nous pouvions itérer les listes exactement deux fois, je peux fournir une méthode pour déterminer le point de fusion:

  • itérer les deux listes et calculer les longueurs A et B
  • calculer la différence des longueurs C = | AB |;
  • commencez à itérer les deux listes simultanément, mais faites des étapes C supplémentaires sur la liste qui était plus grande
  • ces deux pointeurs se rencontreront au point de fusion

8

Voici une solution, rapide sur le plan du calcul (itère chaque liste une fois) mais utilise beaucoup de mémoire:

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
C'est l'équivalent de traiter une liste deux fois.
Georg Schölly

Je suppose que, techniquement, vous faites des choses avec les listes deux fois, mais c'est une amélioration significative de la solution de Kyle Rozendo. Maintenant, si «traiter la liste» est défini comme «lire la valeur du lien et suivre le pointeur», on pourrait dire qu'il traite la liste une fois - il lit chaque valeur de lien une fois, la stocke puis la compare.
Skizz

Va certainement être plus rapide que le mien, sans aucun doute.
Kyle Rosendo

7

Vous pouvez utiliser un ensemble de nœuds. Parcourez une liste et ajoutez chaque nœud à l'ensemble. Ensuite, parcourez la deuxième liste et pour chaque itération, vérifiez si le nœud existe dans l'ensemble. Si c'est le cas, vous avez trouvé votre point de fusion :)


J'ai peur (à cause de l'espace supplémentaire Ω (n)) que ce soit la seule approche (pas une sorte de reconstruction de la (des) liste (s) et) de ne pas analyser une liste plus d'une fois. La détection d'une boucle dans la liste est triviale pour la première liste (vérifiez si le nœud est dans l'ensemble) - utilisez n'importe quelle méthode de détection de boucle sur la deuxième liste pour assurer la terminaison. (La question de l'entrevue portait peut -être sur l'écoute attentive d'un énoncé de problème et ne pas sauter pour utiliser un marteau que vous savez par hasard pour frapper quelque chose qui n'est pas tout à fait un clou.)
greybeard

6

Cela viole sans doute la condition "analyser chaque liste une seule fois", mais implémente l' algorithme de la tortue et du lièvre (utilisé pour trouver le point de fusion et la longueur du cycle d'une liste cyclique) de sorte que vous commencez à la liste A, et lorsque vous atteignez le NULL à la fin, vous faites comme si c'était un pointeur vers le début de la liste B, créant ainsi l'apparence d'une liste cyclique. L'algorithme vous dira alors exactement jusqu'où se trouve la fusion dans la liste A (la variable «mu» selon la description de Wikipedia).

En outre, la valeur "lambda" vous indique la longueur de la liste B, et si vous le souhaitez, vous pouvez calculer la longueur de la liste A pendant l'algorithme (lorsque vous redirigez le lien NULL).


À peu près ce que j'ai dit, juste avec des noms plus chics. : P
Kyle Rosendo

Pas du tout. Cette solution est O (n) dans les opérations et O (1) dans l'utilisation de la mémoire (en fait, ne nécessite que deux variables de pointeur).
Artelius

Oui, j'aurais dû supprimer mon commentaire précédent car ma solution a un peu changé. Hehe.
Kyle Rosendo

Mais je ne vois pas comment cela était applicable en premier lieu?
Artelius

Votre explication l'a fait, pas l'algorithme lui-même. Peut-être que je vois les choses différemment, mais bon.
Kyle Rosendo

3

Peut-être que je simplifie trop cela, mais je répète simplement la plus petite liste et j'utilise les derniers nœuds Linkcomme point de fusion?

Alors, où Data->Link->Link == NULLest le point final, en donnant Data->Linkcomme point de fusion (à la fin de la liste).

ÉDITER:

D'accord, d'après la photo que vous avez postée, vous analysez les deux listes, la plus petite en premier. Avec la plus petite liste, vous pouvez conserver les références au nœud suivant. Maintenant, lorsque vous analysez la deuxième liste, vous faites une comparaison sur la référence pour trouver où Reference [i] est la référence à LinkedList [i] -> Link. Cela donnera le point de fusion. Il est temps d'expliquer avec des images (superposez les valeurs sur l'image de l'OP).

Vous avez une liste chaînée (références ci-dessous):

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

Vous avez une deuxième liste chaînée:

1->2->

Avec la liste fusionnée, les références iraient alors comme suit:

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

Par conséquent, vous mappez la première liste "plus petite" (comme la liste fusionnée, ce que nous comptons, a une longueur de 4 et la liste principale 5)

Parcourez la première liste, conservez une référence de références.

La liste contiendra les références suivantes Pointers { 1, 2, D, E }.

Nous parcourons maintenant la deuxième liste:

-> 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.

Bien sûr, vous maintenez une nouvelle liste de pointeurs, mais ce n'est pas en dehors des spécifications. Cependant, la première liste est analysée exactement une fois, et la deuxième liste ne sera entièrement analysée que s'il n'y a pas de point de fusion. Sinon, il se terminera plus tôt (au point de fusion).


Cela change légèrement de ce que je voulais dire au début, mais de ce que l'OP semble vouloir, cela fera l'affaire.
Kyle Rosendo

C'est plus clair maintenant. Mais linéaire dans l'utilisation de la mémoire. Je n'aime pas ça.
Artelius

La question n'en demandait pas plus, sinon tout le processus peut être multithread. Il s'agit toujours d'une vue simpliste "de haut niveau" de la solution, le code peut être implémenté de plusieurs façons. :)
Kyle Rosendo

1
Quoi? Le multithreading est un moyen de mieux utiliser la puissance de traitement, et non de réduire la puissance de traitement totale requise par un algorithme. Et dire que le code peut être implémenté de plusieurs façons n'est qu'une excuse.
Artelius

1
Cela plie vraiment «analyser chaque liste une seule fois» au point de rupture. Tout ce que vous faites est de copier une liste, puis de vérifier l'autre liste par rapport à la copie.
Skizz

3

J'ai testé un cas de fusion sur mon FC9 x86_64 et j'imprime chaque adresse de nœud comme indiqué ci-dessous:

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


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

Notez parce que j'avais aligné la structure du nœud, donc lorsque malloc () est un nœud, l'adresse est alignée avec 16 octets, voir les 4 bits au moins. Les moindres bits sont des 0, c'est-à-dire 0x0 ou 000b. Donc, si vous êtes également dans le même cas particulier (adresse de nœud alignée), vous pouvez utiliser ces 4 bits au moins. Par exemple, lorsque vous parcourez les deux listes de la tête à la queue, définissez 1 ou 2 des 4 bits de l'adresse du nœud de visite, c'est-à-dire définissez un drapeau;

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

Notez que les indicateurs ci-dessus n'affecteront pas l'adresse réelle du nœud mais uniquement la valeur de votre pointeur de nœud SAVED.

Une fois trouvé, quelqu'un a défini le ou les bits d'indicateur, le premier nœud trouvé devrait être le point de fusion. une fois terminé, vous restaureriez l'adresse du nœud en effaçant les bits d'indicateur que vous aviez définis. tandis qu'une chose importante est que vous devez être prudent lors de l'itération (par exemple, node = node-> next) pour faire clean. souvenez-vous que vous aviez défini des bits de drapeau, alors faites de cette façon

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

Étant donné que cette proposition restaurera les adresses de nœud modifiées, elle pourrait être considérée comme "aucune modification".


+1, c'est ce qui me vient naturellement à l'esprit avec "itérer une seule fois" je ne sais pas pourquoi cela n'a jamais été voté! Belle solution.
jman

3

Il peut y avoir une solution simple mais nécessitera un espace auxiliaire. L'idée est de parcourir une liste et de stocker chaque adresse dans une carte de hachage, de parcourir maintenant l'autre liste et de faire correspondre si l'adresse se trouve dans la carte de hachage ou non. Chaque liste n'est parcourue qu'une seule fois. Il n'y a aucune modification à aucune liste. La longueur est encore inconnue. Espace auxiliaire utilisé: O (n) où 'n' est la longueur de la première liste parcourue.


2

cette solution n'itère chaque liste qu'une seule fois ... aucune modification de la liste n'est également requise ... bien que vous puissiez vous plaindre de l'espace ..
1) En gros, vous itérez dans list1 et stockez l'adresse de chaque nœud dans un tableau (qui stocke la valeur int non signée)
2) Ensuite, vous parcourez list2, et pour l'adresse de chaque nœud ---> vous recherchez dans le tableau que vous trouvez une correspondance ou non ... si vous le faites, c'est le nœud de fusion

//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;
} 

J'espère que c'est une solution valable ...


Cela itère à peu près une des listes plus d'une fois, bien que sous la forme d'un tableau au lieu de la liste elle-même.
syockit le

1

Il n'est pas nécessaire de modifier une liste. Il existe une solution dans laquelle nous n'avons à parcourir chaque liste qu'une seule fois.

  1. Créez deux piles, disons stck1 et stck2.
  2. Parcourez la 1ère liste et envoyez une copie de chaque nœud que vous traversez dans stck1.
  3. Identique à la deuxième étape mais cette fois traversez la 2ème liste et poussez la copie des nœuds dans stck2.
  4. Maintenant, sortez des deux piles et vérifiez si les deux nœuds sont égaux, si oui, gardez une référence à eux. Si non, alors les nœuds précédents qui étaient égaux sont en fait le point de fusion que nous recherchions.

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;
}

Dans sa révision initiale, cela ne faisait qu'énoncer la réponse la plus votée (Pavel Radzivilovsky, 2013) .
greybeard

0

Voici une solution naïve, pas besoin de parcourir des listes entières.

si votre nœud structuré a trois champs comme

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

disons que vous avez deux têtes (head1 et head2) pointant vers la tête de deux listes.

Parcourez à la fois la liste au même rythme et mettez le drapeau = 1 (drapeau visité) pour ce nœud,

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

0

Que dis-tu de ça:

  1. Si vous n'êtes autorisé à parcourir chaque liste qu'une seule fois, vous pouvez créer un nouveau nœud, parcourir la première liste pour que chaque nœud pointe vers ce nouveau nœud, et parcourir la deuxième liste pour voir si un nœud pointe vers votre nouveau nœud ( c'est votre point de fusion). Si le deuxième parcours ne mène pas à votre nouveau nœud, les listes d'origine n'ont pas de point de fusion.

  2. Si vous êtes autorisé à parcourir les listes plus d'une fois, vous pouvez parcourir chaque liste pour trouver leurs longueurs et si elles sont différentes, omettez les nœuds "supplémentaires" au début de la liste plus longue. Ensuite, parcourez simplement les deux listes une étape à la fois et trouvez le premier nœud de fusion.


1. non seulement modifie mais détruit la première liste. 2. est suggéré à maintes reprises.
greybeard

0

Étapes en Java:

  1. Créez une carte.
  2. Commencez à parcourir les deux branches de la liste et placez tous les nœuds traversés de la liste dans la carte en utilisant quelque chose d'unique lié aux nœuds (par exemple, l'ID de nœud) comme clé et mettez Valeurs comme 1 dans le début pour tous.
  3. À chaque fois que la première clé dupliquée arrive, incrémentez la valeur de cette clé (disons maintenant que sa valeur devient 2, ce qui est> 1.
  4. Obtenez la clé où la valeur est supérieure à 1 et qui doit être le nœud où deux listes fusionnent.

1
Et si nous avons un cycle dans la partie fusionnée?
Rohit

Mais pour les cycles de gestion des erreurs, cela ressemble beaucoup à la réponse isyi .
greybeard

0

Nous pouvons le résoudre efficacement en introduisant le champ "isVisited". Parcourez la première liste et définissez la valeur "isVisited" sur "true" pour tous les nœuds jusqu'à la fin. Maintenant, commencez par le deuxième et trouvez le premier nœud où flag est vrai et Boom, c'est votre point de fusion.


0

Étape 1: trouver la longueur des deux listes Étape 2: Trouvez le diff et déplacez la plus grande liste avec la différence Étape 3: Les deux listes seront maintenant dans une position similaire. Étape 4: Parcourez la liste pour trouver le point de fusion

//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

(J'ai mieux aimé la liste avec chaque élément commençant une ligne. Pensez à utiliser un vérificateur d'orthographe.)
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;
}

Vous devez ajouter quelques explications à votre réponse. Les réponses au code uniquement peuvent être supprimées.
rghome

0

Utilisez la carte ou le dictionnaire pour stocker l'adresse et la valeur du nœud. si l'adresse existe déjà dans la carte / le dictionnaire, la valeur de la clé est la réponse. J'ai fait ça:

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

Solution de complexité AO (n). Mais basé sur une hypothèse.

l'hypothèse est: les deux nœuds n'ont que des entiers positifs.

logique: rend tout l'entier de list1 négatif. Parcourez ensuite la liste2, jusqu'à ce que vous obteniez un entier négatif. Une fois trouvé => prenez-le, changez le signe en positif et revenez.

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

Nous pouvons utiliser deux pointeurs et nous déplacer de telle sorte que si l'un des pointeurs est nul, nous le pointons vers la tête de l'autre liste et même pour l'autre, de cette façon si les longueurs de la liste sont différentes, ils se rencontreront dans la deuxième passe . Si la longueur de list1 est n et list2 est m, leur différence est d = abs (nm). Ils couvriront cette distance et se retrouveront au point de fusion.
Code:

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

Vous pouvez ajouter les nœuds de list1à un hashset et la boucle à travers le second et si un nœud de list2est déjà présent dans l'ensemble .Si oui, alors c'est le nœud de fusion

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

Solution utilisant 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

Si la modification de la liste liée est autorisée,

  1. Ensuite, faites simplement les pointeurs de nœud suivant de tous les nœuds de la liste 2 comme nuls.
  2. Trouvez la valeur de données du dernier nœud de la liste 1. Cela vous donnera le nœud intersectant en un seul parcours des deux listes, sans "aucune logique hi-fi".
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.