描述
给定一个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
进阶:
你能用 O(1)(即,常量)内存解决此问题吗?
思路1:双指针
1.首先要考虑到[]和[1]这种情况,这两类测试用例不可能有环,直接返回false。
2.定义两个快慢指针,一个速度快,一个速度慢。只要快指针能追上慢指针,那么必定有环,返回true。如果没有环,那么快指针必定会先到达链表末尾,此时返回false。
3.空间复杂度:只使用了常数个额外空间,所以为O(1)。
4.时间复杂度:
(1)若不存在环,快指针会先到达链表尾,事件复杂度取决于链表长度,即O(n)。
(2)若存在环,快慢指针会在环中运动,快指针一定会追上慢指针,最长不会超过环的长度,环的长度最大不会超过链表结点数n,所以也是O(n)。
解答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) {
if (head == NULL || head->next == NULL) return false;
ListNode* pFast = head;//快指针
ListNode* pLow = head;//慢指针
while(pFast && pFast->next){//leetcode要求判断pFast->next是否空指针
pFast = pFast->next->next;
pLow = pLow->next;
if(pFast == pLow) return true;
}
return false;
}
};
思路2:Hash表
1.建立一个哈希表,标记每个结点是否被访问过,若再次被访问,说明有环。
2.时间复杂度O(n),每个结点至多遍历一次。
3.这方法耗空间比较多,哈希表中添加的个数取决于结点个数n,所以是O(n)。
解答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) {
if(head == NULL) return false;
unordered_map<ListNode*, bool> map;
unordered_map<ListNode*, bool>::iterator it;
while(head){
if((it = map.find(head)) != map.end()) return true;
map[head];
head = head->next;
}
return false;
}
};