(题目来源:力扣)
一.判读一个链表是否是环形链表
题目:
解答:
方法:快慢指针法
内容:分别定义快慢指针(fast和slow),快指针一次走两步,慢指针一次走一步。
原理:若不成环,则快指针(或快指针的next)一定会走到空,据此,写出循环条件,当循环结束时,返回NULL
while(fast&&fast->next)
此时,问题来了,成环怎么办?不能再通过循环条件来判断(因为此时该循环是死循环了)
目光再回到快慢指针上,若成环,则快指针一定会有追上慢指针的时候,当它们相遇时,循环结束
证明:
解题代码(并非完整代码)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode *head)
{
struct ListNode* fast = head;
struct ListNode* slow = head;
while(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if(fast == slow)
{
return true;
}
}
return false;
}
拓展:
总结:当N为奇数,C为偶数时,二者一直错过,无法相遇
真的是这样吗?
C是偶数且N是奇数,这个条件能同时满足吗?
不妨推导一下:
(fast走n步的情况就交给读者自行思考了)
二.找到环形链表开始进入环的第一个节点
题目:
解答:
设进入环的第一个节点为 ptail
1.先判断是否是环形链表(同上)
2.找到开始进入环的第一个节点
方法:
先定义快慢指针:fast和slow,fast一次走两步,slow一次走一步
先让fast和slow相遇,定义meet指针指向相遇节点
定义一个新指针newhead 指向链表的头结点,然后让newhead和meet指针同时向前走,他们相遇的节点就是ptail
证明:
解题代码(非完整代码)
struct ListNode *detectCycle(struct ListNode *head)
{
//先判断有无环,并找到相遇时的节点
struct ListNode* fast = head;
struct ListNode* slow = head;
struct ListNode* meet = NULL;
while(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
//相遇
if(fast == slow)
{
meet = fast;
struct ListNode* newhead = head;
while(newhead != meet)
{
newhead = newhead->next;
meet = meet->next;
}
return meet;
}
}
return NULL;
}