题目描述
141.环形链表
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
示例1
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例2
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例3
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
进阶
你能用 O(1)(即,常量)内存解决此问题吗?
解题思路
1.双指针
刚开始的思路是设里双指针,二层循环遍历链表,如果有环,则快指针必能追上慢指针,当两指针相等时,返回true,否则返回false。
但在执行过程中,若链表有环,则内层循环无法跳出,形成死循环,导致失败。
时间复杂度 O(n^2)
额外空间 O(1)
代码如下:
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head == NULL) return false;
ListNode* p = head;
while(p->next != NULL)
{
ListNode* q = p->next;
while(q->next != NULL)
{
if(p == q)
{
return true;
}
q = q->next;
}
p = p->next;
}
return false;
}
};
2.散列表
根据两数之和思路,单指针遍历链表
建立unordered_map<ListNode*, int>
将该容器key设为指针,val设为链表所对应的val形成一一映射,则若出现指针相同情况,则说明链表有环,return true,否则return false
代码如下:
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head == NULL) return false;
unordered_map<ListNode*, int> map;
ListNode* p = head;
while(p->next != NULL)
{
if(map[p])
{
return true;
}
map[p] = p->val;
p = p->next;
}
return false;
}
};
执行结果
3.快慢指针
看完题解之后发现原来双指针可以不用两次循环,而是通过两指针每次前进“步幅”不同而实现快慢指针,若链表中有环,则快指针必能追上慢指针,当两指针相遇时,return true,否则return false。
时间复杂度 O(n)
额外空间 O(1)
代码如下:
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head == NULL) return false;
ListNode* p = head->next;
while(p != NULL && p->next != NULL)
{
if(p == head)
{
return true;
}
head = head->next;
p = p->next->next;
}
return false;
}
};