获取有环单向列表环入口的结点(双指针法)

LeetCode 141.环形链表 142.环形链表II

对题目不熟悉的同学,可以先刷下题,结合LeetCode上的题解和评论

前不久刷算法题,用快慢指针法求解141题判断链表是否有环。随后开始解142题,用了HashMap的解法,结果看评论区的大佬还是用双指针法来求解。大佬的解题分两个步骤

步骤一:使用快慢指针判断链表是否有环

步骤二:找到入环开始的节点

要完成步骤一很简单,步骤一就是141题的解法。这不是本篇文章要讲的内容。那么我们如何找到入环开始的节点呢?

引用@算法小菜 大佬的解题思路如下:

解题思路:分两个步骤,首先通过快慢指针的方法判断链表是否有环;接下来如果有环,则寻找入环的第一个节点。具体的方法为,首先假定链表起点到入环的第一个节点A的长度为a【未知】,到快慢指针相遇的节点B的长度为(a + b)【这个长度是已知的】。现在我们想知道a的值,注意到快指针p2始终是慢指针p走过长度的2倍,所以慢指针p从B继续走(a + b)又能回到B点,如果只走a个长度就能回到节点A。但是a的值是不知道的,解决思路是曲线救国,注意到起点到A的长度是a,那么可以用一个从起点开始的新指针q和从节点B开始的慢指针p同步走,相遇的地方必然是入环的第一个节点A。文字有点绕,画个图就一目了然了~~

看完了解题思路还是懵逼。然后这道题就被我搁置了半个月,今天看到公众号上有一篇文章上有找到入环开始的节点的内容,作者引入了很多个变量来解答s,a,b,n,r,L,X。

更懵了好吗?并且网上这样的文章很多,大家有兴趣可以去搜索一下。

废话不多说,现在开始讲解双指针法解题思路。先上图


我们直接跳过步骤一:使用快慢指针判断链表是否有环。讲解步骤二

定义

链表头结点到环入口的长度为:a

首次相遇的点到环入口的长度为:b

我们使用快慢指针求相遇的点,当快慢指针首次相遇时,得到如下公式

一:慢指针走过的路程为 a  +  b;

二:快指针走过的路程为 2a+2b;

推导

我们不再引入其余的变量来计算,现在开始推导

我们想象一下当快指针走过的路程为 2a+b时,停留在哪个位置(不考虑快指针一次走两步的问题)?

答案是快指针走过路程为2a+b时,停留在环入口的结点

好的,那我们再想象一下,当快指针走过的路程为a+b时,停留的位置?这个就不用考虑了,慢指针在与快指针首次相遇时正好走过a+b的路程。

所以答案是快指针走过路程为a+b时,停留在首次相遇的结点。

由此,我们可以得出结论首次相遇的结点走a的距离可以到达环入口结点。(这里可能存在的a比环的长度更大的情况)

解题

要获取有环单向列表环入口的节点,只需要两个慢指针p1,p2分别从首次相遇的结点链表头结点开始遍历。

p1从链表头结点a步到达入环结点

p2从首次相遇的结点a步到达入环结点

p1,p2必然在入环节点相遇

代码如下:

public ListNode detectCycle(ListNode head) {                                                                                                                        if (head == null || head.next == null) {                                                                                                                                     return null;                                                                                                                                                                      }                                                                                                                                                                                             ListNode fast = head, low = head;                                                                                                                                     while (fast != null && fast.next != null) {                                                                                                                                    fast = fast.next.next;                                                                                                                                                             low = low.next;                                                                                                                                                                       if (fast == low) break;                                                                                                                                                     }                                                                                                                                                                                              if (fast == null || fast.next == null) return null;                                                                                                                             ListNode p1 = fast, p2 = head;                                                                                                                                             while (p1 != p2) {                                                                                                                                                                          p1 = p1.next;                                                                                                                                                                          p2 = p2.next;                                                                                                                                                                     }                                                                                                                                                                                        return p1;

}


写在最后的话

实际上@算法小菜 大佬要表达的就是这个意思,居然时隔半个月之后才懂。还是需要自己多思考!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,247评论 6 543
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,520评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,362评论 0 383
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,805评论 1 317
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,541评论 6 412
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,896评论 1 328
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,887评论 3 447
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,062评论 0 290
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,608评论 1 336
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,356评论 3 358
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,555评论 1 374
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,077评论 5 364
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,769评论 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,175评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,489评论 1 295
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,289评论 3 400
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,516评论 2 379