1. 程式人生 > >Leetcode:Linked List Cycle II

Leetcode:Linked List Cycle II

所有 public clas 因此 包含 表頭 class return node

題目大意:判斷一個鏈表是否含有環,如果有環則輸出距離鏈表頭最近的環上結點(即從鏈表頭出發進入環的入口)。


  有趣的題目,一般判斷鏈表是否有環可以同時使用兩個軌跡結點遍歷整個鏈表,且軌跡結點速度不同,快者q每次循環移動兩步,慢者s每次循環移動一步。這樣如果有環,那麽快者必定會在環上追趕上慢者(由於二者相對速度為1,故快者不可能越過慢者),而且快者和慢者必定會在n次循環內相遇(或者快者遇到null),n為鏈表的長度。

  下面說一下如果獲得距離鏈表頭最近的結點。假設環的入口距離鏈表頭n個結點,而q與s在距離環入口m個結點處相遇,q與s在第k次循環相遇。由於慢者在進入環時快者已經進入,故慢者不可能完全遍歷環,由此可以得出n+m=k。前面提到的所有變量只有k是已知的,我們的目標是求出n。

  先假設環由c個結點組成,可以推出:$$ 2k-L=k-L\left(mod\ c\right)\Rightarrow n+m=pc $$

  這也意味著當一個軌跡結點從快者和慢者相遇處出發,每次循環前進一步,在n次循環後將回到環的入口處。雖然我們不知道n的具體值,但是請查看n的定義,是入口距離鏈表頭的距離,因此當我們設置兩個軌跡結點x和y同時分別從相遇處和鏈表頭出發,當二者首次相遇時,就是環處,所移動的步數,就是環距離鏈表頭的距離。

  利用這個算法,可以在O(n)時間復雜度內(n為鏈表中包含的結點數)找到環的入口(兩次循環操作的時間復雜度都不超過O(n)),空間復雜度由於只使用了常量個變量故為O(1)。


技術分享
 1 public class Solution {
 2     public ListNode detectCycle(ListNode head) {
 3         if(head == null || head.next == null)
 4         {
 5             return null;
 6         }
 7         
 8         ListNode fast = head.next.next;
 9         ListNode slow = head.next;
10         
11         while
(fast != slow) 12 { 13 if(fast == null || fast.next == null) 14 { 15 return null; 16 } 17 fast = fast.next.next; 18 slow = slow.next; 19 } 20 21 ListNode a = head; 22 ListNode b = slow; 23 24 while(a != b) 25 { 26 a = a.next; 27 b = b.next; 28 } 29 return a; 30 } 31 }
View Code

Leetcode:Linked List Cycle II