簡體   English   中英

循環鏈表邏輯

[英]Circular linked list logic

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head == null){
            return false;
        }
          ListNode slow = head;
          ListNode fast = head.next;

          while((slow != null) && (fast != null) && (slow.next != null) && (fast.next != null)){
            if(slow == fast){
                return true;
            }
            slow = slow.next;
            fast = fast.next.next;

          }

          return false;
    }
}

為了檢測循環鏈表,我們使用2指針技術,慢速和快速。

我的問題是,如果列表是循環列表,我怎么知道指針必須在某些點交叉?

看一下手表。 這是一個數字1到12的循環列表,然后回到1。

大手快速移動,小手移動緩慢,向同一方向移動,從同一點開始(頂部= 12)。

因為列表(邊緣)是圓形的,所以大手最終會回到小手上。 速度有多快取決於速度差異,但它會趕上來。 如果它趕上,列表必須是循環的。

如果它沒有趕上,但到達列表的末尾,則列表不是循環的。

即使列表沒有回到開頭,例如如果12圈回到9,快手只會繼續盤旋,直到小手進入圓圈,然后快手最終會趕上小手。

好吧,對於最后一部分,手表的形象並不好,但我希望你明白這一點。

證據並不像看起來那么明顯。

實際上,通過稍微改變可以使快速指針更快, 例如使用fast = fast.next.next.next ,該算法不再保證可以工作。

重要的是兩個指針的相對速度。

在標准情況下,相對速度為2 - 1 = 1,這意味着在每一步,快速指針都會獲得一個靠近慢速指針的單位。 通過這種方式,可以保證快速的一個能夠趕上而不會跳過另一個。

否則, 例如,如果相對速度是3 - 1 = 2,那么它們可能永遠不會相交。 如果我們從指針之間的奇數距離開始,並且周期長度是偶數,則會發生這種情況。 在這種情況下,距離始終保持為奇數(因此它永遠不會為零)。


為了清楚指示如果不注意速度差異,指針可能不相交,請考慮速度為3的快速指針和速度為1的慢速指針,運行在一個帶有4個節點的循環中,標記為0,1,2, 3,形成一個像這樣的循環0 - > 1 - > 2 - > 3 - > 0。

假設最初,慢速指針位於節點0,快速指針位於節點1.(請注意,這不是一個強大的假設,並且可能無法通過不同的初始化策略來緩解 - 無論初始化方法如何,它都可能如果圖中有一些額外的節點,而不是循環的一部分,那么指針一旦到達循環就可以處於任意位置)。

k步之后,慢指針將在節點k mod 4 快節點將位於節點(1 + 3k) mod 4 假設存在k使得快指針和慢指針處於相同位置,則意味着(1 + 3k) mod 4 = k mod 4 (1 + 2k) mod 4 = 0 但左側是奇數,因此它不能為零。 因此,指針可以指向同一節點的假設導致矛盾。

好吧,正如andreas提到的那樣看看手表,但如果仍然沒有意義,那么可能會有所幫助。

此外,您可以稍微簡化您的代碼:

public boolean isCyclic(Node first) {
    if(first == null) {
      return false;
    }
    Node fast = first;
    Node slow = first;
    while(fast.getNext() != null && fast.getNext().getNext() != null) {
      slow = slow.getNext();
      fast = fast.getNext().getNext();
      if(slow == fast) {
        return true;
      }
    }
    return false;
}

我還認為你應該用head而不是head.next初始化你的快速指針

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM