题一:环形链表(I)
思路(快慢指针)
slow 每次走一步
fast 每次走两步
关于快慢指针[数据结构初阶] | OJ | 【快慢指针】 | 【思路+源码】题:链表的中间结点、链表倒数第k个结点、回文结构
但是这里有一个很重要的问题,这个 “环”不同于现实生活中的跑道,它不是由连续的路程组成,而是由单个不可分的结点组成,所以,fast和slow一定会相遇吗?
关键在于slow和fast是1和2的关系👇
- 首先,fast肯定比slow先进入环(如果有的话),当slow也进入环,就开始了“追逐”,而fast每次都比slow多走一个,即速度差为1,所以每过一次fast和slow之间的差距就-1
- 假设,fast与slow之间的差距是N,那么随着 “追逐”,就会有如下变化:
- N-1 → N-2 → N-3 → …………→ 0(相遇)
那么,slow每走1步,fast走3、4、5、……步行不行?
同上的思路,假设,fast与slow之间的差距是N,那么随着“追逐”,就会有如下变化: N-2→ N-4 → N-6 → …………→可能会减到0,也可能从一个正数减到一个负数
- 首先,如果是空链表肯定return NULL;
- 定义两个快慢指针
- while循环,在fast和slow都不走到空的情况下,看fast和slow能不能相遇,如果相遇返回真
- 如果fast和slow跳出循环,即其中有一个走到了NULL,则返回假
源码
bool hasCycle(struct ListNode *head)
{
if(!head)
return false;
struct ListNode *slow=head,*fast=head;
while(slow&&fast)
{
if(fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(slow==fast)
return true;
}
else
return false;
}
return false;
}
题二:环形链表(II)(找入环点)
题目链接:142. 环形链表 II - 力扣(LeetCode)
思路
思路一:承接上题
- slow 每次走一步;fast 每次走两步
- 因此,fast的路程一定是slow的两倍,但是,这里还有一个要考虑的事情,fast可能在环里走了很多圈之后slow才进环(slow肯定没走完一圈,根据上面关于“追逐”部分的分析可知)
- 首先我们得找判断是不是有环,如果有我们得找到meet,思路参考题一
- 利用如上结论找到入环点
struct ListNode *detectCycle(struct ListNode *head) {
if(!head)
return NULL;
struct ListNode *slow=head,*fast=head;
struct ListNode *meet=head;
struct ListNode *cur=head;
while(slow&&fast)
{
if(fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(slow==fast)
{
meet=slow;
while(meet!=cur)
{
cur=cur->next;
meet=meet->next;
}
return meet;
}
}
else
return NULL;
}
return NULL;
}
思路二:把环从
meet
处断开(但是还是的找到 meet 哈)