力扣-142-环形链表Ⅱ
看起来仿佛跟Ⅰ没什么区别,但是事实上这里要返回环的起始节点,而Ⅰ只需要返回true/false
而且这里要求O(1)
的空间复杂度
对应O(N)
的空间复杂度是,每遍历一个节点,判断set中是否有这个节点,有就返回
还是用Ⅰ中的最优解法:快慢双指针
快指针两步一走,慢指针一步一走,原理是这样的:
- 对于有环的链表:快指针会先进入循环,并重复在循环中跑…能否保证当两个指针相遇时一定同时指向循环的其实节点?
假设链表长度n,循环段长m,当快指针进入循环,快指针走了n步,慢指针走了n/2步,他俩相差
|n/2+m|
,则慢指针再走了这么长之后,快指针追上它了,此时满指针和快指针的值都为m+n
,满指针此时指向…第m个元素…
好吧,快慢指针是用来求有没有环而不是求环的起始节点是谁的,但知道了m、n长度的话,似乎也能做出来
啊,瞄一眼题解,当他俩相遇的时候,再来一个指针指向头节点,然后和快慢中的一个同步移动,当新指针指向n-m位置(走了n-m-1步),快慢指针走完n步,又指向循环的开始节点,他俩相遇
这里步数不一样,那就多走一步
ListNode* detectCycle(ListNode* head) { // 这里不用&&而是用||,防止head为空,出现空指针异常 // 为什么||就没有空指针异常? if (!head || !head->next) return nullptr; // 如果头节点或者头节点的下一个节点为空,即长度为0或1,一定没有环 ListNode* slow = head, * beginOfCircle = head, * fast = head->next; // 这里的写法要避免空指针异常 while (slow != fast) { // 这里不需要判断slow,它一定在fast后面,sfast判断过就行 if (!fast || !fast->next) return nullptr; slow = slow->next; fast = fast->next->next; } slow=slow->next; while (beginOfCircle != slow) { // 这里一定有环,就不用判断空指针了 slow = slow->next; beginOfCircle = beginOfCircle->next; } return beginOfCircle; }
不优雅的实现
那么到底slow走了多少步?总的时间复杂度m+n+m-n=2m
本文作者:Yao's Blog
本文链接:https://www.cnblogs.com/yaocy/p/16844975.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步