求單鏈表中環的起點,原理詳解

1. 問題描述:

鏈表結構如下,若鏈表中有環,返回環的起點,否則返回NULL

1 struct ListNode
2 {
3     int val;
4     ListNode *next;
5     ListNode(const int val):val(val),next(NULL) {}
6 };

 

 2. 解題代碼:

參考 LeetCode

 1 ListNode *detectCycle2(ListNode *head) {
 2     if(!head) return head;
 3     ListNode *stepA = head;// 每次走一步
 4     ListNode *stepB = head;// 每次走兩步
 5     while (stepB && stepB->next) {
 6         stepA = stepA->next;
 7         stepB = stepB->next->next;
 8         if(stepA==stepB){
 9             ListNode *stepC = head;
10             while (stepC != stepA) {
11                 stepC = stepC->next;
12                 stepA = stepA->next;
13             }
14             return stepC;
15         }
16     }
17     return NULL;
18 }

 

3. 原理詳解:

(1)假設鏈表頭到環起點的距離爲S1,環的長度爲S0;在環中相遇時stepA走的路程是SA,stepB走的路程是SB。則當SB>=SA>=S1時,以下結論成立:

(SA-S1) mod S0 = (SB-S1) mod S0    <=>   (SB-SA) mod S0 = 0   <=>   SB-SA = n*S0   <=>   SA=n*S0;  (SB>=SA>=S1)

 

a. 因爲stepB的速度是stepA速度的兩倍,所以SB=2SA;

b. 所以 SB-SA=SA=nS0>=S1;

c. 所以 n>=S1/S0,n爲自然數

d. 結論:只要滿足條件 n>=S1/S0,則stepA和stepB就會在環上相遇;

e. 第一次相遇時 n 的值爲 S1/S0 向上取整,假設此時 n=n1,則 SA=n1*S0

 

(2)stepA和stepB第一次在環上相遇後,讓stepB停下,stepC從表頭開始走,stepA從當前位置走,並且stepA和stepC一次只走一步。

 假設在環上相遇時stepA走的路程是SAA,stepC走的路程是SC,則當SC>=S1時,以下結論成立:

(SC-S1) mod S0 = (SAA-S1) mod S0    <=>   (SAA-SC) mod S0 = 0     <=>   (SC+n1*S0-SC) mod S0 = 0     <=>   (n1*S0) mod S0 = 0;  (SC>=S1)

a. 因爲stepA和stepC的速度相同,所以等式SA A= SC+n1*S0成立;

b. 所以(SAA-SC) mod S0 = 0     <=>   (SC+n1*S0-SC) mod S0 = 0     <=>   (n1*S0) mod S0 = 0

c. 因爲 (n1*S0) mod S0 = 0 恆成立,所以 stepA和stepC在環上相遇也恆成立,只要滿足SC>=S1就行;

d. stepA和stepC在環上第一次相遇時,SC=S1,此時stepC正好在環的起點。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章