今天在牛客上做题,遇到两次环形链表,晚上回来小结一下。
题目描述
对于一个给定的链表,返回环的入口节点,如果没有环,返回null
快慢指针法
想象一下,有两个速度不同的跑步者。如果他们在直路上行驶,快跑者将首先到达目的地。但是,如果它们在圆形跑道上跑步,那么快跑者如果继续跑步就会追上慢跑者。
这正是我们在链表中使用两个速度不同的指针时会遇到的情况:
A.如果没有环,快指针将停在链表的末尾。
B.如果有环,快指针最终将与慢指针相遇。
Q:这两个指针的适当速度应该是多少?
一个安全的选择是每次移动慢指针一步,而移动快指针两步。每一次迭代,快速指针将额外移动一步。如果环的长度为 M,经过 M 次迭代后,快指针肯定会多绕环一周,并赶上慢指针。
时间复杂度:O(n)
空间复杂度:O(1)
struct ListNode
{
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
题一:
class Solution
{
public:
ListNode *detectCycle(ListNode *head)
{
/*
快慢指针:
快指针走两步,慢指针走一步.
两者相遇后,将快指针指向头结点--->从走两步变为走一步,这时候快慢指针相遇的地方必为第一个环节点相遇。
*/
if (!head || !head->next) return NULL;
ListNode* pFast = head;
ListNode* pSlow = head;
do
{
if (!pFast || !pFast->next)
{
return NULL;
}
pFast = pFast->next->next;
pSlow = pSlow->next;
} while (pSlow != pFast);
pSlow = head;
while (pSlow != pFast)
{
pSlow = pSlow->next;
pFast = pFast->next;
}
return pSlow;
}
};
题二:
class Solution {
public:
bool hasCycle(ListNode *head)
{
//快慢指针相遇就是有环!
if (!head || !head->next) return false;
ListNode* pFast = head;
ListNode* pSlow = head;
while (pFast && pFast->next)
{
pFast = pFast->next->next;
pSlow = pSlow->next;
if (pSlow == pFast)
{
return true;
}
}
return false;
}
};