141. 环形链表 - 力扣(LeetCode)
如图所示环状链表中的pos可以指向链表中任意位置。并且
因此我们想到一个思路是:快慢指针。
slow走一步,fast走两步:
fast先进入圈中开始循环,当slow进入到圈中时开始fast开始追击。
bool hasCycle(struct ListNode *head) {
if(head == NULL || head->next == NULL)//head的next成员,可能导致程序崩溃或产生未定义的行为,应该先判断head是否为NULL,再判断head->next是否为NULL
{
return false;
}
struct ListNode *fast = head;
struct ListNode *slow = head;
while(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if(slow == fast)
{
return true;
}
}
return false;
}
这个时候链表只有两个节点,即使第一个节点指向第二个节点,但是由于没有形成闭环,所以也应该返回false ,所以我们应该先迭代再判断。
代码的实现是非常简单的,我们再来看看以下常见问题:
1、为什么一定要相遇,有没有可能错过,或者追不上?
2、slow一次走一步,fast一次走3步,或走4步....
证明:1、为什么一定要相遇,有没有可能错过,或者追不上?
假设slow进环时,fast跟slow的距离为N
fast追击slow过程中的距离变化如下:
证明:2、slow一次走一步,fast一次走3步,或走4步....
fast追击slow的距离N变化有两种情况分别为偶数和奇数情况:
如果N是奇数C是偶数那么就追不上。
我们再来考虑一下是否永远不存在追不上的问题:
142. 环形链表 II - 力扣(LeetCode)https://leetcode.cn/problems/linked-list-cycle-ii/description/
struct ListNode *detectCycle(struct ListNode *head) {
if(head == NULL || head->next == NULL)
{
return NULL;
}
struct ListNode *fast = head;
struct ListNode *slow = head;
while(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if(slow == fast)
{
struct ListNode *meet = slow;
while(meet != head)
{
head = head->next;
meet = meet->next;
}
return meet;
}
}
return NULL;
}
这里运用的是数学思想:
思路2:
设置一个新的结点newhead让他存储meet->next,再让meet指向null,此时我们只需要让head从头往后走,当与newhead相遇时则返回此时的值,跟思路1一样,思路1是用meet进行,而我们的思路二只需要使head与newhead相交。
//相交代码
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode *curA = headA;
struct ListNode *curB = headB;
int lenA = 0;
int lenB = 0;
while(curA)
{
++lenA;
curA = curA->next;
}
while(curB)
{
++lenB;
curB = curB->next;
}
curA = headA;
curB = headB;
int gap = abs(lenA - lenB);
if(lenA > lenB)
{
while(gap--)
{
curA = curA->next;
}
}
else
{
while(gap--)
{
curB = curB->next;
}
}
while(curA && curB)
{
if(curA == curB)
{
return curA;
}
curA = curA->next;
curB = curB->next;
}
return NULL;
}
//查找代码
struct ListNode *detectCycle(struct ListNode *head) {
if(head == NULL || head->next == NULL)
{
return NULL;
}
struct ListNode *fast = head;
struct ListNode *slow = head;
while(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if(slow == fast)
{
struct ListNode *meet = slow;
struct ListNode *newhead = meet->next;
meet->next = NULL;
return getIntersectionNode(head,newhead);
}
}
return NULL;
}