題目:
Given a linked list, determine if it has a cycle in it.
Follow up:
Can you solve it without using extra space?
題解:
這道題連帶著II是很經典的,在看CC150時候,糾結這個問題糾結了很久。在讀了很多網上資料還有書的講解以及和別人討論之後,對這個專題終於明白了。
這一問只需要判斷連結串列是否有環。
當連結串列沒有環時是很好判斷的,讓一個指標一直往後走,遇見null了自然就沒有環。
而如何判斷有環,那麼就需要引入Faster和Slower的概念了(也是一種雙指標方法)。顧名思義,同個時間Faster走的比Slower走的多。一般來說,Slower每次走一步,Faster每次走2步(通常這個概念可以判斷連結串列中間點)。在這裡,Faster和Slower同時從起點遍歷連結串列,如果有環那麼Slower和Faster肯定會相遇。
為什麼他倆肯定能相遇呢?萬一一個把一個超了但是沒相遇咋辦?
直覺和生活經驗告訴我,他倆肯定能相遇,比如在操場跑圈,一個快的一個慢的同時開始跑,一直跑,快的肯定能跟慢的相遇。不過有更嚴謹的說法就更有說服力了。
下面我就引用一下CC150裡面外加我的完善來說明怎麼證明的這個問題:
假設Faster確實把Slower超了而且他倆還沒相遇(類似Faster一下邁了2步,Slower一下邁了一步,Faster超了Slower,但是倆人並沒遇上)。那麼就假設Faster現在在 i+1 位置而Slower在 i 位置。那麼前一時刻,Slower肯定是在 i-1 位置,而Faster肯定在(i+1)-2位置,所以前一時刻,倆人都在 i-1 位置,相遇了。
還有一種情況就是Faster在i+2位置而slower在i位置,那麼前一時刻,Faster在i位置,而Slower在 i-1位置。這樣問題又迴歸到上面那種情況了(再往前一時刻,Faster在i-2位置,Slower在i-1-1位置,相遇)。
所以,這就證明Runner和Faster在有環的連結串列中肯定會相遇。
程式碼工作就很簡單了,如下:
2 if(head == null || head.next == null)
3 return false;
4
5 ListNode Faster = head, Slower = head;
6
7 while(Faster.next!=null && Faster.next.next!=null){
8 Slower = Slower.next;
9 Faster = Faster.next.next;
10
11 if(Faster == Slower)
12 return true;
13 }
14 return false;
15 }