環型鏈表
題目描述:
- 給定一個鏈表,判斷鏈表當中有沒有環
解體思路:
思路一:
- 可以利用快慢指針的思路,給定兩個指針,讓兩個指針一開始都位於鏈表頭部的位置,然後開始走起來,一個指針每次走一步,一個指針每次走2步,如果說鏈表是有環的話,那麼走的快的鏈表,就會先進入到環裏面,然後一直在環裏面繞圈圈,慢的指針也會一步一步走到環的裏面,如果有環的話,那麼最終兩個指針一定是會相遇的,那麼就可以通過快慢指針去判斷鏈表裏面到底有沒有環。
- 代碼如下所示:
/**
* 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)
{
ListNode *fast=head;
ListNode *slow=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(fast==slow)
return true;
}
return false;
}
};
- 還有一個問題需要去考慮------就是
快的指針走3步,慢的指針走一步可以嗎?—答案是不可以的,因爲如果快的指針和慢的指針的差值剛好是鏈表的長度的話,那麼就算鏈表有環,快的指針和慢的指針也是不可能會相遇的,那麼爲什麼要一個走一步,一個走兩步呢?----因爲鏈表中至少是要有一個結點的,而且1這個數字是可以被任意的數字所整除的。當兩個指針都進入到環裏面的時候,那麼兩個指針的之間的差值就是一直在縮小的,一直在縮小,那麼到最後肯定是會相遇的。
快慢指針的複雜度分析
思路二:利用哈希表
- 哈希表法:每訪問一個結點,檢查該結點是否在哈希表中,如果在,則說明存在環,return true;否則,將該結點加入哈希表中。最終,若不存在環,遍歷將結束,然後return false。就是看每個結點被訪問的次數,一旦有一個結點被訪問的次數是大於1的,那麼這個鏈表就一定是存在環的
/**
* 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)
{
unordered_map <ListNode *,int> ret;
while(head)
{
ret[head]++;
if(ret[head] > 1)
return true;
head = head->next;
}
return false;
}
};