链表带环问题及其扩展问题

leetcode141.

思路: 快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表起始位置同时开始运行,如果链表带环则一定会在链表中相遇,否则快指针率先走到链表末尾。
代码如下
 

bool hasCycle(struct ListNode *head) {
    struct ListNode*slow=head,*fast=head;
    //fast分为奇数个和偶数个
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
         if(slow==fast)
         return true;
    }
    return false;
}

 【扩展问题】
为什么快指针每次走两步,慢指针走一步可以
假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。当慢指针刚 进环时,可能就和快指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。 此时,两个指针每移动一次,之间的距离就缩小一步,,因此:在满指针走到一圈之前,快指针肯定是可以追上慢指针的,即相遇。

 假设slow进环时,fast和slow之间的距离为N
slow进环后,fast和slow的距离变化,每次追击距离缩小1.


快指针一次走三步,走四步,.....n步行吗?
我们这里假设slow一次走一步,fast一次走三步

 当slow走到一定的时候fast已经入圈了。


假设slow进环时,fast和slow之间的距离为N 

 slow进环后,fast和slow的距离变化,每次追击距离缩小2
1.N是偶数下一圈直接相遇。
2.N是奇数,N为奇数遇到刚好错过
距离为-1代表,新一轮的开始,这个距离C-1(假设C是环的长度)
1.C-1是奇数,继续追击,陷入循环。
不成立

2.C-1是偶数,下一圈直接相遇。
总结:
1.N如果是偶数直接追上。
2.如果N是奇数,C是奇数,第一轮错过,但第二轮追上

3.如果N是奇数,C是偶数,就永远追不上。
不成立

所以一定能追上。
证明:

假设slow进环时,fast和slow之间的距离为N

 起点到环入口点:L
slow入环的时候,fast-slow的距离是N
环的长度为c
slow入环的时候慢指针走的路程:L
快指针走的路程:L+n*C-N(n>=1)
快指针走的路程是慢指针的3倍
3L=L+n*C-N
2L=n*C-N
如果N是奇数,C是偶数,就永远追不上
2L=n*C-N
偶数=n*偶数-奇数:不成立
 

leetcode142.

 

 结论: 让一个指针从链表起始位置开始遍历链表,同时让一个指针从判环时相遇点的位置开始绕环 运行,两个指针都是每次均走一步,最终肯定会在入口点的位置相遇。

 

1. 假设慢指针走一步,快指针走两步。

起点到环入口点:L
入口点到相遇点:X
环的长度:C

从开始相遇时slow走的距离:L+X
从开始相遇时fast走的距离:L+n*C+X(slow进环前,fast已经在环里面转了n圈)
fast路程=slow路程*2
2*(L+X)=L+n*C+x
L+X==n*C
L=n*C-X

结论:一个指针从相遇点开始走,一个指针从头开始走,他们会在入口点相遇

快慢指针求出相遇点,然后,一个指针从相遇点开始走,一个指针从头开始走,走到循环入口点代码如下:
 

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode*slow=head,*fast=head;
    while(fast&&fast->next)
    {
       slow=slow->next;
       fast=fast->next->next;
       if(slow==fast)
       {
       //相遇点
       struct ListNode*meet=slow;
       while(head!=meet)
       {
           //同时走
           head=head->next;
           meet=meet->next;
       }
       return head;
       }
       
    }
    return NULL;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值