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:
- Nous ne connaissons pas la longueur
- Nous ne devrions analyser chaque liste qu'une seule fois.
Réponses:
Si
l'algorithme suivant serait la solution.
Premièrement, les chiffres. Supposons que la première liste est de longueur
a+c
et la seconde est de longueurb+c
, oùc
est la longueur de leur "queue" commune (après le point de fusion). Notons-les comme suit:Puisque nous ne connaissons pas la longueur, nous allons calculer
x
ety
sans 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+1
total des itérations. Appelons çaz+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:
À partir de laquelle nous déterminons que
Ce qui résout le problème.
la source
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.
la source
a-b-c-x-y-z
etp-q-x-y-z
. chemin du premier pointeura,b,c,x,y,z,p,q,x
, chemin du deuxième pointeurp,q,x,y,z,a,b,c,x
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.
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.
la source
Eh bien, si vous savez qu'ils fusionneront:
Disons que vous commencez par:
1) Parcourez la première liste en définissant chaque pointeur suivant sur NULL.
Maintenant vous avez:
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.
la source
Si nous pouvions itérer les listes exactement deux fois, je peux fournir une méthode pour déterminer le point de fusion:
la source
Voici une solution, rapide sur le plan du calcul (itère chaque liste une fois) mais utilise beaucoup de mémoire:
la source
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 :)
la source
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).
la source
Peut-être que je simplifie trop cela, mais je répète simplement la plus petite liste et j'utilise les derniers nœuds
Link
comme point de fusion?Alors, où
Data->Link->Link == NULL
est le point final, en donnantData->Link
comme 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:
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).
la source
J'ai testé un cas de fusion sur mon FC9 x86_64 et j'imprime chaque adresse de nœud comme indiqué ci-dessous:
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;
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
Étant donné que cette proposition restaurera les adresses de nœud modifiées, elle pourrait être considérée comme "aucune modification".
la source
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.
la source
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
J'espère que c'est une solution valable ...
la source
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.
la source
la source
Voici une solution naïve, pas besoin de parcourir des listes entières.
si votre nœud structuré a trois champs comme
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,
la source
Que dis-tu de ça:
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.
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.
la source
Étapes en Java:
la source
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.
la source
É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
la source
la source
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:
la source
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.
la source
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:
la source
Vous pouvez ajouter les nœuds de
list1
à un hashset et la boucle à travers le second et si un nœud delist2
est déjà présent dans l'ensemble .Si oui, alors c'est le nœud de fusionla source
Solution utilisant javascript
la source
Si la modification de la liste liée est autorisée,
la source