力扣-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 中国大陆许可协议进行许可。

posted @   YaosGHC  阅读(20)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起