环型链表
题目描述:
- 给定一个链表,判断链表当中有没有环
解体思路:
思路一:
- 可以利用快慢指针的思路,给定两个指针,让两个指针一开始都位于链表头部的位置,然后开始走起来,一个指针每次走一步,一个指针每次走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;
}
};