44import com .rampatra .base .SingleLinkedNode ;
55
66/**
7- * Created by IntelliJ IDEA.
7+ * See this <a href="https://stackoverflow.com/a/32190575/1385441">Stackoverflow post</a> to understand
8+ * how to find the starting node of the loop.
9+ * <p>
10+ * Proof for Flyod's Loop Detection Algorithm:
11+ * <p>
12+ * Suppose fastRunner had just skipped over slowRunner. fastRunner would only be 1 node ahead of slowRunner, since their
13+ * speeds differ by only 1. So we would have something like this:
14+ * <p>
15+ * [ ] -> [s] -> [f]
16+ * <p>
17+ * What would the step right before this "skipping step" look like? fastRunner would be 2 nodes back, and slowRunner
18+ * would be 1 node back. But wait, that means they would be at the same node! So fastRunner didn't skip over slowRunner!
19+ * (This is a proof by contradiction.)
820 *
921 * @author rampatra
1022 * @since 7/1/15
11- * @time: 12:39 PM
1223 */
1324public class DetectAndRemoveLoop {
1425
1526 /**
16- * Detects loop if any in {@param list} and removes it.
17- * <p>
18- * Algorithm:
27+ * Detects loop, if any, in {@code list} and removes it.
1928 * <p>
29+ * Approach:
2030 * 1) Use Floyd's cycle detection algorithm to detect loop.
2131 * 2) Acc. to FCD, once the fast pointer meets the slow pointer we conclude that there is a loop.
22- * 3 ) Now compute the length 'l' of the loop.
23- * 4) Move the fast pointer length 'l' from head.
24- * 5) Now move both slow and fast pointer at same pace and where they meet is the starting point of the loop.
25- * 6) Lastly, to remove the loop make the next of the node (before the starting point of loop) to null.
32+ * 4 ) Now that we have concluded there is a loop, let's detect the starting node and remove the loop:
33+ * i. Move the slow pointer to head.
34+ * ii. Now, move both slow and fast pointer at same pace and where they meet is the starting point of the loop.
35+ * iii. Lastly, to remove the loop make the next of the node (before the starting point of loop) to null.
2636 *
2737 * @param list
2838 * @param <E>
2939 * @return {@code true} if loop exists {@code false} otherwise.
3040 */
3141 public static <E extends Comparable <E >> boolean detectAndRemoveLoop (SingleLinkedList <E > list ) {
32- int i = 0 , length = 0 ;
3342 boolean isLoopPresent = false ;
34- SingleLinkedNode <E > slow = list .head , fast = slow . next ;
43+ SingleLinkedNode <E > slow = list .head , fast = list . head ;
3544
3645 while (fast != null && fast .next != null ) {
46+ slow = slow .next ;
47+ fast = fast .next .next ;
3748 if (slow == fast ) {
3849 isLoopPresent = true ;
3950 break ;
4051 }
41- slow = slow .next ;
42- fast = fast .next .next ;
4352 }
4453
45- if (isLoopPresent == false ) return false ;
46-
47- // compute length of loop
48- while (fast .next != slow ) {
49- fast = fast .next ;
50- length ++;
51- }
52-
53- // move fast pointer from head by the length of loop
54- slow = fast = list .head ;
55- while (i <= length ) {
56- fast = fast .next ;
57- i ++;
58- }
54+ if (!isLoopPresent ) return false ;
5955
56+ slow = list .head ;
6057 // move both pointers at same pace to determine the starting node of loop
6158 while (true ) {
6259 slow = slow .next ;
@@ -72,14 +69,14 @@ public static <E extends Comparable<E>> boolean detectAndRemoveLoop(SingleLinked
7269
7370 public static void main (String [] args ) {
7471 SingleLinkedList <Integer > linkedList = new SingleLinkedList <>();
75- linkedList .add (00 );
76- linkedList .add (11 );
77- linkedList .add (22 );
78- linkedList .add (33 );
79- linkedList .add (44 );
80- linkedList .add (55 );
81- linkedList .getNode (1 ).next = linkedList .getNode (0 );
72+ linkedList .add (0 );
73+ linkedList .add (1 );
74+ linkedList .add (2 );
75+ linkedList .add (3 );
76+ linkedList .add (4 );
77+ linkedList .add (5 );
78+ linkedList .getNode (4 ).next = linkedList .getNode (2 );
8279 System .out .println (detectAndRemoveLoop (linkedList ));
8380 linkedList .printList ();
8481 }
85- }
82+ }
0 commit comments