1. 程式人生 > >LintCode: 帶環連結串列 + 帶環連結串列 II

LintCode: 帶環連結串列 + 帶環連結串列 II

1. 帶環連結串列

描述

給定一個連結串列,判斷它是否有環。

樣例

給出 -21->10->4->5, tail connects to node index 1,返回 true

挑戰

不要使用額外的空間


思路: 可以先看上面這個圖,a 是 起點,b 是 環的起點,b到d是一個環。

這個c點是什麼呢,下面我們來說說。

首先連結串列的題目,我們首先會想到快慢指標,沒錯,這道題就用到了快慢指標。 c 就是快慢指標第一次相遇的 那個地點。

x代表起點a到環的起點b的距離,y代表環的起點到第一次相遇地點c的距離, z代表環剩下的長度。 長度l 代表環的長度,

即 y+z。

再看下面兩個公式: v代表 慢指標走的長度, 2v代表 快指標走的長度。

v = x +y + m * l 

2v = x + y + n * l 

運算上面兩個式子,可以得到:

x + y = (n-2m)*l

繼續運算,可以得到:

x = (n-2*m-1)*l + l - y = (n-2*m-1)*l + z.

可以知道,x的長度是任意環的長度加上z的長度,那麼現在一個點從a開始出發,一個點從c點出發,每次前進一步,等它們相遇的時候,就正好在起點b處了。

2. 帶環連結串列 II

描述

給定一個連結串列,如果連結串列中存在環,則返回到連結串列中環的起始節點,如果沒有環,返回null。

樣例

給出 -21->10->4->5, tail connects to node index 1

,返回10

挑戰

不使用額外的空間

題目 1, 2 的思路都在上邊了,下面給出Java實現程式碼:

1. 

    public boolean hasCycle(ListNode head) {
        // write your code here
        ListNode fast = head;
        ListNode slow = head;
        while (fast!=null && fast.next!=null){
            slow = slow.next;
            fast = fast.next.next;
            if(slow==fast){
                return true;
            }
        }
        return false;
    }

2. 

public ListNode detectCycle1(ListNode head) {
        // write your code here
        if(head==null || head.next==null || head.next.next==null){
            return null;
        }
        boolean flag = false;
        ListNode fast = head;
        ListNode slow = head;
        while (fast!=null && fast.next!=null){
            slow = slow.next;
            fast = fast.next.next;
            if(slow==fast){
                flag = true;
                break;
            }
        }
        if(flag){
            while (head != slow){
                head = head.next;
                slow = slow.next;
            }
            return head;
        }
        return null;
    }