Solution 1 - gracieuseté de Career Cup et du livre "Cracking the Coding Interview":
public static LinkedListNode findStartOfLoop(LinkedListNode head) {
LinkedListNode n1 = head;
LinkedListNode n2 = head;
// trouver le point de rencontre en utilisant l'algorithme de la tortue et du lièvre
// c'est simplement l'algorithme de détection de cycle de Floyd
while (n2.next != null) {
n1 = n1.next;
n2 = n2.next.next;
if (n1 == n2) {
break;
}
}
// Vérification d'erreur - il n'y a pas de point de rencontre, donc pas de boucle
if (n2.next == null) {
return null;
}
/* Déplacer n1 à Head. Garder n2 au point de rencontre. Chacun est k pas
de la boucle. S'ils se déplacent à la même vitesse, ils doivent nécessairement
se rencontrer au début de la boucle. */
n1 = head;
while (n1 != n2) {
n1 = n1.next;
n2 = n2.next;
}
// Maintenant, n2 pointe vers le début de la boucle.
return n2;
}
L'explication de cette solution vient directement du livre :
Si nous déplaçons deux pointeurs, l'un avec vitesse 1 et un autre avec vitesse 2, ils finiront par se rencontrer si la liste chaînée a une boucle. Pourquoi ? Pensez à deux voitures roulant sur une piste : la voiture la plus rapide passera toujours devant la plus lente !
La partie délicate ici est de trouver le début de la boucle. Imaginez, par analogie, deux personnes courir autour d'une piste, l'une courant deux fois plus vite que l'autre. S'ils commencent au même endroit, quand se rencontreront-ils ? Ils se rencontreront au début du prochain tour.
Maintenant, supposons que le coureur rapide ait une longueur d'avance de k mètres sur un tour de n étapes. Quand se rencontreront-ils la prochaine fois ? Ils se rencontreront k mètres avant le début du prochain tour. (Pourquoi ? Le coureur rapide aura fait k + 2(n - k) pas, comprenant son avance, et le coureur lent aura fait n - k pas. Les deux seront à k pas avant le début de la boucle.)
Maintenant, revenant au problème, lorsque le coureur rapide (n2) et le coureur lent (n1) se déplacent autour de notre liste chaînée circulaire, n2 aura un avantage de départ sur la boucle lorsque n1 entre. Spécifiquement, il aura un avantage de k, où k est le nombre de nœuds avant la boucle. Puisque n2 a un avantage de k nœuds, n1 et n2 se rencontreront k nœuds avant le début de la boucle.
Nous savons maintenant ce qui suit :
- La tête est k noeuds du début de la boucle (par définition)
- Le point de rencontre pour n1 et n2 est k noeuds du début de la boucle (comme montré ci-dessus)
Ainsi, si nous ramenons n1 à la tête et gardons n2 au point de rencontre, et les déplaçons tous les deux à la même vitesse, ils se rencontreront au début de la boucle
Solution 2 - gracieuseté de moi :)
public static LinkedListNode findHeadOfLoop(LinkedListNode head) {
int indexeur = 0;
Map map = new IdentityHashMap();
map.put(head, indexeur);
indexeur++;
// commence à parcourir la liste tout en plaçant chaque nœud dans la HashMap
// si nous arrivons à un nœud qui est déjà dans la liste,
// alors ce nœud est le début du cycle
LinkedListNode curr = head;
while (curr != null) {
if (map.containsKey(curr.next)) {
curr = curr.next;
break;
}
curr = curr.next;
map.put(curr, indexeur);
indexeur++;
}
return curr;
}
J'espère que cela vous aidera.
Hristo
1 votes
Pouvez-vous définir ce qu'est une boucle?
0 votes
@Enrique - OP voulait probablement dire une liste circulaire.
0 votes
@Enrique : Modifier ma question pour plus de détails, merci de me donner du temps
1 votes
Étroitement lié à nomachetejuggling.com/2014/06/24/…