今天 LeetCode 的每日一题是 142. 环形链表 II,最优解好神奇。看了 视频讲解 才搞懂,整理下作为笔记。
视频中讲解了如下几个算法:
与本题相关的是 1 ~ 3 ,算法也比较类似。
1. 计算链表的中间节点
算法:
- 定义两个指针
slow和fast指向head; slow每次向后走一步,fast每次向后走两步;- 直到
fast是最后一个节点或最后一个节点之后的null时,此时slow节点即是中间节点。
说明:
-
奇数个节点的场景
-
偶数个节点的场景
代码:
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
return null;
}
}
return slow;
2. 是否是环形链表
算法:
- 定义两个指针
slow和fast指向head; slow每次向后走一步,fast每次向后走两步;- 直到
fast和slow指向相同的节点,则表明链表中存在环形链路。如果不存在环形链路,则fast会先到达终点。
说明:
为什么说 fast 和 slow 指向相同的节点就表明链表中存在环形链路呢?
如果链表中有环路,则慢指针 slow 一定会进入环内(此时快指针 fast 也已经进入了环内)。在环内快指针 fast 相对于慢指针 slow 的相对速度为 1 ,继续走下去快指针一定会追上慢指针。
代码:
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
return true;
}
}
return false;
3. 查找环形链表的入口节点
算法:
- 定义两个游标
slow和fast指向head; slow每次向后走一步,fast每次向后走两步;- 直到
fast和slow指向相同的节点; slow继续单步向下走,同时head也单步向下走(注意这里是head不是fast);- 直到两个指针(
head和slow)相遇,这个相遇的节点就是环形链表的入口节点。
说明:
前面 3 步和 2. 是否是环形链表 的算法一样,比较难理解的是最后两步。
slow 和 fast 相遇时的情景如下:
假设:
head到入口的步长 =入口到相遇点的步长 =相遇点到入口的步长 =- 快指针
fast在环中重复移动的次数 =注意: ,原因在于
fast由于走的较快,肯定是先入环,而想要和slow相遇最快是在循环一次后恰好在入口相遇。
则可知:
- 环长 =
- 慢指针
slow移动距离 =慢指针
slow移动距离为什么是 而不是 ( 为慢指针在环中绕圈的次数)。原因在于慢指针到达入口后,不管快指针位于环中何处,总能在
- 最少 步(即,慢指针到达入口时,刚好快指针也到达入口),
- 最多 步(即,慢指针到达入口时,快指针在慢指针的下一个节点)
追上慢指针,也就是不满一圈,所以 肯定为 。
- 快指针
fast移动距离 =
由于快指针移动距离是慢指针的两倍,则可得如下等式:
- →
- →
slow 和 fast 相遇时如图所示:
上述公式变换最后一步的结果意味着 head 若向后移动了 步之后,此时 head 离 入口 的步长为 (即 倍的环长(由于 ,这个步长最小值为 ,也就是说在移动 步之后,head 最多刚刚入环,不可能移动到 入口 之后的节点))。
若 slow 同样向后移动了 步,则 slow 会位于环形的 入口 。
之后 head 继续向后移动 路径的剩余部分(即 )以到达 入口 ,则相当于移动了 。
若 slow 同样向后移动了 步,由于步数是环长的倍数,则 slow 也必然会位于 入口 。
此时两者就会在 入口 处相遇。
总的来说就是,在 slow 和 fast 相遇之后,若 head 和 slow(或 fast )同步单步向后移动,则必然会在移动了 步之后于 入口 处第一次相遇(代码中不需要关心 的值为多少,只需要移动到两者相遇为止)。
代码:
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
while (head != slow) {
slow = slow.next;
head = head.next;
}
return slow;
}
}
return null;
版权声明:本文为博主「佳佳」的原创文章,遵循 CC 4.0 BY-NC-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:www.liujiajia.me/2023/7/30/l…