链表环形问题

文章讲的两个力扣题

环形链表

环形链表||


这两题主要讲思路,而不是代码,这题的代码过于简单,但是思路却异常的难,需要算法公式推导,这两题思路曾出现在大厂的面试题当中。


判断链表是否有环

这题是判断是否有环,这题巧就巧在,如果你不会其他题目,可以用暴力求解法解出来,但是这题是不行的,因为这题会造成死循环,所以没办法使用暴力求解法。

这题使用的是快慢指针的想法。但是要稳定求出快慢指针走几步,需要求解


1. slow走一步,fast走两步 一定能相遇吗?

因为fast比slow快,所以fast先进环,当slow进环时。fast开始追赶slow,只要fast能刚好遇到slow,我们就能判断链表是有环的。但也不排除他们可以会错开,永远追不上的情况

这是slow进环时,fast大概的位置

我们先假设slow和fast的距离为N

 

那么fast开始追赶slow时,距离变化是 N-1...N-2...N-3...直到N=0。当N=0,就是他们相遇的地方,这样就能够判断链表一定有环。所以结论是 当slow走一步 fast走两步 fast一定能相遇


2.slow一次走一步,fast一次走三步 一定能相遇吗?

当slow进环时,假设slow和fast的距离为N,fast开始追赶slow  那么他们的距离变化是N-2...N-4...N-6;这里分两种情况 

当N是偶数时

那么N-2,一直持续下去,N是一定会被减到0的,那么他们一定会相遇

当N是奇数时

那么N-2,只会被减到-1。这时候 我们有需要到另一个变量,就是环的长度,这里我们假设环的长度为C 

 他们的位置是不一定的,只是画个大概。fast一定是在slow的前一个位置,这时他们就错过了

他们的距离变为C-1

这里又分出了两种情况

假设C-1是偶数时

那么他们的距离又重新变成了偶数,那么fast追一圈后,再追就可以追得上

假设C-1时奇数时

那么他们的距离还是奇书,那么fast就永远会跟slow错过,fast永远不会与slow相遇

所以slow走一步,fast走三步,是有3种情况,所以是不一定能相遇


3.slow一次走1步,fast一次走四步,一定能相遇吗?

 同上,当slow进环时,fast开始追赶slow,他们的距离是N,那么他们的距离变化是N-3...N-6...N-9...

当N是奇数时

N-3持续下去,N是会被减到0的,所以一定会追上

当N是偶数时

那么N会被减到-1或者-2,那么他们就错开了。

这里又分出了两种情况

当被减到-1时

他们的位置是fast比slow多一个位置,他们的距离变为C-1

当C-1是偶数时,他们就永远会错开,fast一定不会跟slow相遇

当C-1时奇数时,他们就会相遇

当被减到-2时

他们的位置时fast比slow多两个位置,他们的距离变为C-2

当C-2是偶数时,他们永远会错开,fast一定不会跟slow相遇

当C-2是偶数时,他们就会相遇

结论为 当slow一次走1步 fast一次走四步 共有6种情况 所以时不一定

接下来还有好多种情况,这里就步一一讲解,但是大概的思路时一样的。


当这个链表有环时,我们要挑选绝对能判断这个链表有环的情况,所以要选第一种,因为第一种时不受N和C的限制的,而2,3种情况都会受到影响。

那么这题就迎刃而解了。

环形链表源码

bool hasCycle(struct ListNode *head) {
    struct ListNode* slow = head,*fast=head;
    while(fast && fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;

        if(slow==fast)
        return true;
    }
    return false;
}

判断链表是否有环,并且返回入口点

这里有两种极端情况

 当L比C大的很多时,当slow进环时,fast可能一圈都没走完

当L比C小很多时,当slow进环时,fast可能已经走很多圈了

但是slow进环时,fast开始追slow,fast只需要在一圈内就能跟slow相遇

根据前面的思路

我们就能推导出一个公式:

2*(L+N)=L+M*C+X

简化为

L+N=M*C

也相当于:

L=M*C-N

这里的M代表走了M圈的意思

那么代码就可以实现为,当他们有环时,我们假设他们的相遇点为meet,然后让meet和head(就是链表的头)开始一步一步走,当他们相遇时,他们就是链表的入环口


环形链表||源码

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(meet!=head)
            {
                meet=meet->next;
                head=head->next;
            }
            return meet;
        }
    }
    return NULL;
}

如果文章对您有帮助,希望能收获您的赞,感谢!

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值