前言
环形链表问题,以及找到链表入环的第一个节点。
一、判断链表是否是环形链表
我们定义快慢指针同时指向头指针,让快指针去追慢指针,并且慢指针每次走一步,快指针每次走两步。
少说废话,上图!
bool hasCycle(struct ListNode *head) {
//定义快慢指针,让快指针去追慢指针
struct ListNode *fast = head, *slow = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast)
{
return true;
}
}
return false;
}
扩展
1.slow一次走一步,fast一次走两步,一定能追上吗?请证明:
我来抽象一下图,便于理解:
所以,slow一次走一步,fast一次走两步,此时一定能追上。
2. slow一次走一步,fast一次走三步,一定能追上吗?请证明:
首先:不一定,在特殊场景下可能永远追不上。
3.求出链表的入口点
第一种方法:
struct ListNode *detectCycle(struct ListNode *head) {
//定义快慢指针,让快指针去追慢指针
struct ListNode *fast = head, *slow = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast)
{
struct ListNode *meet = slow;
while (meet != head)
{
meet = meet->next;
head = head->next;
}
return meet;
}
}
return NULL;
}
第二种方法:
next = meet->next;
时间复杂度为O(m + n),空间复杂度为O(1)
struct ListNode* detectCycle(struct ListNode* head) {
//定义快慢指针,让快指针去追慢指针
struct ListNode* fast = head, * slow = head, * tmp = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast)
{
struct ListNode *meet = slow;
//记录meet的下一个节点
struct ListNode *next = meet->next;
struct ListNode *pA = head, *pB = next;
//把meet->next置为空
meet->next = NULL;
while (pA != pB)
{
pA = pA == NULL ? next : pA->next;
pB = pB == NULL ? head : pB->next;
}
return pA;
}
}
return NULL;
}