快慢指针的经典2题

本文介绍了使用快慢指针解决链表环检测的经典问题,以及如何利用快慢指针的速度差找到环的起始位置。通过追击问题的视角解释了原理,并给出了代码示例和证明过程。
摘要由CSDN通过智能技术生成

不同于其他文章对C语言的介绍,本期将为大家带来两道快慢指针的经典题目。

先来看看两道题目吧!

显然第二道是第一道的进阶版,我们便从第一道开始说起。

第一题

这道题要求我们知道是否有环。那么只有两种情况,链表无环,最后会指向NULL;链表有环,最后一直循环。

但是我们不能通过计数的方式来得到,因为链表可能非常长,我们在得到NULL之前,是永远不会知道链表的长度的。

所以这个时候,快慢指针就有了用场。

快指针走两步,慢指针走一步,达到了存在“时间差”的效果。

假设无环存在,那么大部分情况下快指针会先到NULL(如果元素仅有一个,那么两者都会到NULL,这也是while里的判断是fast && fast->next的原因之一)

为什么要用fast && fast->next来判断?原因是链表不一定是偶数个,这样会导致fast->next直接是NULL了,就不存在fast->next->next了。

所以如果跳出while,将直接得到无环的结论,return false。

假设有环存在,快慢指针真正派上了用场。

小学的时候,我们都学过追击问题吧?

这里的快慢指针也可以被视作追击问题的衍生。

有环存在,就意味着快慢指针会同时进入环内。进入环内之后,便是追击问题了。

在环内计算时,直接算相对速度就好。

如果将慢指针的速度视为1的话,那么快指针的速度就是2,相对速度也就是2-1=0。

此刻假设慢指针进入环内的时候,与快指针的位置相差C个单位。

设环的长度为N,易知追上的“时间”是(N-C),也就得到了这种方式可行的结论。

问题延申

如果快慢指针的速度差不为1,为2,为3,能起到一样的效果吗?

即fast=3,slow=1或者fast=4,slow=1这样。

我们开始讨论这个问题。

仍然从追击问题的视角来看这个问题。

fast和slow的相对距离不一定是C,也可能是C+x*N(其中x为未知圈数,N为圈的总长度)

换句话说,fast可能在slow走第一圈时相遇,也有可能在slow走第n圈时相遇......

那么,只需要(C+x*N)能被(n-1)整除,那么就可以相遇。

这意味着,快慢指针的速度差可能会影响是否能追上。

但是当n取2的时候,就一定能追上,因为1整除任何数。

第二题

第二题在第一题的基础上,让我们返回环的起始位置。

我们肯定是选择最简单的情况,即快指针速度是慢指针2倍。

先上代码:

这里用到了一个结论,同时从快慢指针的位置和头结点开始以1的速度走,相遇点就是头节点。

下面证明这个结论:

我们从之前的研究中可以知道,如果快指针是慢指针的两倍,那么一定会在slow的第一圈相遇。

S(slow)=L(环之前的长度)+N(slow已走过的路)

S(fast)=L+x*C(x为圈数,C为整个环的长度)+N(slow已走过的路)

因为S(fast)=2*S(slow)

所以x*C=L+N;

所以L=x*C-N;

那么head走了L的时候,meet位置走了x*C-N,从图上就可以看出,meet一定在环的头节点处!

也就是说,当head和meet相遇时即是头结点。

这就是我为大家带来的两道经典题目,如有错误请多指正!

祝各位学习顺利~

  • 18
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值