detecting the start of a loop in a singly linked link list?

Viewed 36161

Is there any way of finding out the start of a loop in a link list using not more than two pointers? I do not want to visit every node and mark it seen and reporting the first node already been seen.Is there any other way to do this?

16 Answers

This is code to find start of loop in linked List :

public static void findStartOfLoop(Node n) {

    Node fast, slow;
    fast = slow = n;
    do {
        fast = fast.next.next;
        slow = slow.next;
    } while (fast != slow);       

    fast = n;
    do {
        fast = fast.next;
        slow = slow.next;
    }while (fast != slow);

    System.out.println(" Start of Loop : " + fast.v);
}

There are two way to find the loops in a link list. 1. Use two pointer one advance one step and other advance two steps if there is loop, in some point both pointer get the same value and never reach to null. But if there is no loop pointer reaches to null in one point and both pointer never get the same value. But in this approach we can get there is a loop in the link list but we can't tell where exactly starting the loop. This is not the efficient way as well.

  1. Use a hash function in such a way that the value should be unique. Incase if we are trying to insert the duplicate it should through the exception. Then travel through each node and push the address into the hash. If the pointer reach to null and no exception from the hash means there is no cycle in the link list. If we are getting any exception from hash means there is a cycle in the list and that is the link from which the cycle is starting.
  1. Take two pointers, one fast and one slow. The slow pointer moves one node at a time, the fast pointer moves two nodes at a time, ultimately they'll meet and you'll find the loop.
  2. Now comes the fun part, how do you detect the loop? That's simple as well. Let me ask you another fun question first: How will you go about searching for the n-x the node in the list in one pass? The simple answer will be to take two pointers, one at the head, one at x steps ahead of the head and move them at the same speed, when the second pointer hits the end, the first one will be at n-x.
  3. As many other people have mathematically proved in this thread if one pointer moves at twice the speed of one pointer, the distance from start to the point at where they meet is going to be a multiple of the length of the list. Why is this the case?? As fast pointer is moving at twice the speed of slow pointer, can we agree that: Distance travelled by fast pointer = 2 * (Distance travelled by slow pointer)

now:

  1. If m is the length of the loop(nodes in the loop) that has no cyle

  2. If n is the actual length of the loop.

  3. x is the number of cycles slow pointer made

  4. y is the number of cycles fast pointer made.

  5. And K is the distance from the start of the loop to the point of meeting

  6. Note that this point is the only piece of length in the path of both the pointers that are going to be extra after their number of cycles of the loop. So besides this k rest of what they travelled are cycles of the loop and the initial distance from the head to the start of the loop. Hence, both are travelling m+n*(numbers of cycles they made) + k distance after their cycles at which they met each other. So, we can say that:

    (m + nx + k) = 2(m + n*y + k)

  7. When you solve this mathematically you'll discover that m+k is a multiple of the length of the loop that is n. i.e. [m + k = (x-2y)*n]

  8. So, if you maintain a distance that is a multiple of the length and move eventually you'll meet again at the start of the loop. Why? Can't they meet somewhere else? Well fast is already at k and slow is at the head, if they both travel m distance as k+m is the multiple of n, fast would be at the start of the loop. While if slow travels m distance it'll meet k as m is the distance from head to start of the loop as we originally assumed m to be.

  9. Hence, it is mathematically proved that the distance which both the the fast and slow pointer will have to travel if set the slow pointer to head again after detecting the loop and make them both travel at the The same speed is going to be m.

public class Solution {
    public ListNode detectCycle(ListNode head) {
        if(head==null||head.next==null)return null;
        ListNode slow = head;
        ListNode fast = head;
        while(fast.next!=null&&fast.next.next!=null){
            slow = slow.next;
            fast = fast.next.next;
            if(fast==slow){
                slow=head;
                while(slow!=fast){
                    slow=slow.next;
                    fast=fast.next;
                }
                return slow;
            }
        }
        return null;
    }
}

Pythonic code solution based on @hrishikeshmishra solution

def check_loop_index(head):
    if head == None or head.next == None:
        return -1
    
    slow = head.next
    if head.next.next == None:
        return  -1
    fast = head.next.next
    
    # searching for  loops exists or not
    while fast and fast.next:
        if slow==fast:
            break
        slow = slow.next
        fast = fast.next.next
    
    # checking if there is loop 
    if slow != fast:
        return -1
    
    # reseting the slow to head and creating index
    index = 0
    slow = head
    
    # incrementing slow and fast by 1 step and incrmeenting index, if they meet 
    # hen thats the index of node where loop starts
    while slow!=fast:
        slow = slow.next
        fast = fast.next
        index+=1

    return index
Related