快慢指標法總結 連結串列找環 leetcode 141 142 & 202
阿新 • • 發佈:2018-11-11
前言
- 這類題,做法很簡單,但是我每次證明正確性的時候總是卡殼,所以這次整理一版我個人覺得比較清晰的證明,希望能以後能記住。。
思路
- 題型特點:給你一個連結串列,或者只知道遞推關係的資料(形如初始是
,遞推關係是
O(1)
空間集線性時間裡,判斷資料是否有環,進一步會問環起點是哪個資料 - 判斷是否有環演算法:兩個指標,慢指標每次走一步,快指標每次走兩步,能相遇則有環,否則無
- 找環起點演算法:在上一步基礎上,從相遇點各出發一個指標,每次走一步,再相遇點就是環起點
- 證明判斷有環演算法,若有環則一定會相遇:
- 設在
t
時刻相遇,無環段長 , 有環段長 ,則有
- 兩式相減得到: ,
- 則能相遇的條件是,滿足對任意
,存在
- 顯然可以令 , 足夠大就可以滿足上述條件
- 設在
- 證明第二個演算法中相遇點是環頭:
- 把上一個證明中的兩個等式消元掉
t
,並換元簡化一下式子,得到
- 我們的目的,是得到 ,根據等式,顯然分別從頭和 的位置出發,最後會在 相遇
- 把上一個證明中的兩個等式消元掉
leetcode相關題目
141. Linked List Cycle
- 判斷連結串列是否有環
- 實現:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
if (!head)
return false;
auto slow = head, fast = head;
do {
if (fast->next == NULL || fast->next->next == NULL)
return false;
fast = fast->next->next;
slow = slow->next;
}while (slow != fast);
return true;
}
};
142. Linked List Cycle II
- 找環頭
- 實現:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if (!head)
return NULL;
auto slow = head, fast = head;
do {
if (fast->next == NULL || fast->next->next == NULL)
{
fast = NULL;
break;
}
fast = fast->next->next;
slow = slow->next;
}while (slow != fast);
if (!fast)
return NULL;
slow = head;
while (slow != fast){
fast = fast->next;
slow = slow->next;
}
return fast;
}
};
202. Happy Number
- 給定next函式和初始值
n
,next為n
的各十進位制位的平方和 - 求最後能否變為
1
- 思路:我們會發現,不管初始
n
多大,由於是int值,經過一次變換後,最大不會超過1000
- 完全可以通過判斷是否提前有環來解
- 實現:
class Solution {
public:
int next(int x){
int ret = 0;
while (x > 0){
ret += (x % 10) * (x % 10);
x /= 10;
}
return ret;
}
bool isHappy(int n) {
int slow = n, fast = n;
do{
slow = next(slow);
fast = next(fast);
fast = next(fast);
if (fast == 1)
return true;
}while(slow != fast);
return false;
}
};