Solution 1 - Courtesy of the Career Cup and the book Cracking the Coding Interview :
public static LinkedListNode findStartOfLoop(LinkedListNode head) { LinkedListNode n1 = head; LinkedListNode n2 = head;
An explanation of this solution directly from the book:
If we move two pointers, one with speed 1 and the other with speed 2, they will end the meeting if the linked list has a loop. What for? Think of two cars moving along the track; a faster car will always go slower!
The hard part here is finding the beginning of the cycle. Imagine, as an analogue, two people racing along the highway, one running twice as fast as the others. If they start from the same place, when will they follow next time? They will meet at the beginning of the next lap.
Now let's assume that Fast Runner had an entry level of k meters n step. When will they follow meet? They will meet k meters before the start of the next round. (Why? A runner would take k + 2 (n - k) steps, including its beginning, and a Slow runner would take n - k steps. Both will be to steps before the start of the cycle).
Now, returning to the problem, when Fast Runner (n2) and Slow Runner (n1) moves around our circularly linked list, n2 will have a head start on the loop when n1 enters. In particular, it will have an initial start k, where k is the number of nodes before the cycle. Since n2 has an initial start of k nodes, n1 and n2 will correspond to nodes before the start of the cycle.
So now we know the following:
- A chapter is k nodes from LoopStart (by definition)
- MeetingPoint for n1 and n2 are k nodes from LoopStart (as shown above)
So if we move n1 back to Head and save n2 in MeetingPoint and move them both at the same pace, they will meet in LoopStart
Solution 2 - kindly provided by me :)
public static LinkedListNode findHeadOfLoop(LinkedListNode head) { int indexer = 0; Map<LinkedListNode, Integer> map = new IdentityHashMap<LinkedListNode, Integer>(); map.put(head, indexer); indexer++; // start walking along the list while putting each node in the HashMap // if we come to a node that is already in the list, // then that node is the start of the cycle LinkedListNode curr = head; while (curr != null) { if (map.containsKey(curr.next)) { curr = curr.next; break; } curr = curr.next; map.put(curr, indexer); indexer++; } return curr; }
Hope this helps. Christo