[LintCode] Linked List Cycle I & II

442 查看

Linked List Cycle I

Problem

Given a linked list, determine if it has a cycle in it.

Example

Given -21->10->4->5, tail connects to node index 1, return true

Note

做法:如果有环,快慢指针必定可以相遇。
注意两点:初始化快慢指针的时候,fast要在slow后面,也就是head.next;由于fast一次走两步,所以while循环里要判断两个位置是否为nullfastfast.next

Solution

public class Solution {
    public boolean hasCycle(ListNode head) {  
        if (head == null/* ||head.next == null */) return false;
        ListNode fast = head.next;
        ListNode slow = head;
        while (fast != slow) {
            if (fast == null || fast.next == null) return false;
            fast = fast.next.next;
            slow = slow.next;
        }
        return true;
    }
}

Linked List Cycle II

Problem

Given a linked list, return the node where the cycle begins.

If there is no cycle, return null.

Example

Given -21->10->4->5, tail connects to node index 1,return 10.

Note

画一个简图:

a: length of non-loop 非环直线的长度
b: length of loop     环的长度
x: the point slow and fast meet in the loop 快慢指针在环内相遇的位置

--------oooo
        o  o
        ooxo

(a+x)*2 = a-1+kb+x --> a = kb-1-x, slow needs to go kb-x longer to finish the loop.
so if head wants to go to the start point of the loop, it would pass a, the same for slow. After head went a, slow went kb-x-1. However, a = kb-x-1, so head is slow.next at the loop, which is the start point of the loop.

slow在fast在环里的k处相遇,fast比slow走了两倍的路程,假设非环路和环路长度分别为a和b,且fast已经在环里多走了k圈,所以:
(a+x)*2 = a-1+kb+x --> a = kb-1-x
此时,slow还要走kb-x才能走完整个环。
而让head此时重新从起点出发,以和slow相同的速度,需要走非环路的直线长度a,才能到达环的起点。
那么,head到达环的时候,走了a = kb-1-x:是slow在环内走到环的起点的路程-1
也就是说,slow.next = head,就是第二个while循环结束的条件。

Solution

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