1. 程式人生 > >141.判斷連結串列是否有環操作

141.判斷連結串列是否有環操作

單鏈表與環的情況

1.判斷連結串列是否有環

對於這個問題我們可以採用“快慢指標”的方法。就是有兩個指標fast和slow,開始的時候兩個指標都指向連結串列頭head,然後在每一步操作中slow向

前走一步即:slow = slow->next,而fast每一步向前兩步即:fast = fast->next->next。

由於fast要比slow移動的快,如果有環,fast一定會先進入環,而slow後進入環。當兩個指標都進入環之後,經過一定步的操作之後 二者一定能夠在環上相遇,並且此時slow還沒有繞環一圈,也就是說一定是在slow走完第一圈之前相遇(肯定是在環上進行相遇)。證明可以看下圖:

有環的情況


public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head==null) return false;
        ListNode  walker = head;
        ListNode runner = head;
        //主要考慮前面的情況吧
        //如果是沒有環的情況
      while(runner.next!=null && runner.next.next!=null) 
        {
        //如果沒有環的話,逐步減少差距,總會在一個地方相遇到的情況
walker = walker.next; runner= runner.next.next; if(walker==runner) return true; } //如果是有環的情況 return false; } }

2.判斷一個連結串列是否環,並返回環的開始位置

畫一個圖即可判斷處理, 假設走了K步兩者第一次在環上相遇,此時2K-K=R(R代表環的長度), 所以有K=R假設S代表連結串列起點到環起點的位置,M代表環起點的位置到第一次相遇的地方, R =K=S+M, 所以S = R-M ,當 各種長度的關係

所以當runner和walker在第一次相遇的時候,讓walker回到起點,讓walker走S, 讓runner走 R-M, 由於s=r-m 兩者會在環起點的位置初相遇,

public class Solution {
    public ListNode detectCycle(ListNode head) {
        //有環的話必然是兩個以上的節點
        if(head==null|| head.next==null) return null;
        ListNode walker= head, runner = head;
        boolean mark = false;
        //判斷是否有環程式碼結構
        while(runner.next!=null && runner.next.next!=null){
            walker = walker.next;
            runner= runner.next.next;
            if(runner==walker){
                //第一次相遇即可退出
                mark = true;
                break;
            }
        }
        //沒有環的情況
        if(!mark) return null;
        //有環的情況下兩者相遇在環上,讓runner停留在第一次相遇的地方
        walker = head;
        while(walker!=runner){
            walker = walker.next;
            runner = runner.next;
        }
        return walker;
    }

}

#