一个浪漫的算法(快慢指针)
Posted 小胖java攻城狮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个浪漫的算法(快慢指针)相关的知识,希望对你有一定的参考价值。
伟人说:“对的人值得等,错的人不必等。只要是对的人,兜兜转转终是你。”
点击这里听一路向北
原题目链接: 141. 环形链表
解析:
如何判断一个链表是否有环?采用快慢指正针做法最为便捷,那么什么是快慢指针呢?这其实是一个浪漫的算法。
情况一:
假设有 3,2,0,4 四个节点,我们可以把它们想象成四个城市,然后有个男生叫拓海,有个女生叫夏树,拓海在3城市这个地方,而夏树在2城市这个地方,他们都有各自的生活轨迹,谁也不认识谁。
他们的生活总是向前的,只不过拓海生活节奏比较慢,每次只前进一次,夏树生活节奏快,每次前进两次。
第一天之后变成
第二天之后变成
此时,他们在0城市相遇了,彼此一件钟情,也证明了夏树对于拓海来说是对的人,是有缘分的,是有环的。
等等!!!好像剧情不对!!!还有另一种情况,就是辣个男人出现了。
情况二:
假设有 3,2,0,4 四个节点,我们可以把它们想象成四个城市,然后有个男生叫拓海,有个女生叫夏树,拓海在3城市这个地方,而夏树在2城市这个地方,他们都有各自的生活轨迹,谁也不认识谁。
他们的生活总是向前的,只不过拓海生活节奏比较慢,每次只前进一次,夏树生活节奏快,每次前进两次。
第一天后变成
第二天后变成
此时已经发现,夏树还是选择了奔驰大叔,拓海和夏树还是终究还是错过了,这就说明拓海和夏树是错的人,是没有缘分,没有环的。
这说明,再快的86也追不上奔驰,兄弟们,把爷青结打在评论区上。
代码实现:
如何用代码复现我刚刚说的故事呢?
先准备两个指针,一个慢指针 slow,也就是拓海,一个快指针 fast,也就是夏树,判断 fast 指针是否还能继续走,如果可以,fast 走两步,slow 走一步。
可能存在一个疑惑,那就是为什么在有环的情况下,slow 走一步,fast 走两步,slow 和 fast 就一定会相遇???
这个问题就像两个人以不同的速度在操场跑圈,快的人一定会追上慢的人,画几个图说明一下大家就明白了
例如 slow 与 fast 的距离为n,那么每循环一次,slow 就会向前移动一步,此时slow 与 fast 的距离为 n + 1,但同样的 fast 会向前移动两步,此时slow 与 fast 的距离为 n + 1 - 2,也就是n - 1,那么也就是说,每循环一次,slow 与 fast 的距离就会减1,久而久之,fast 和 slow 就一定会相遇。
public class Solution {
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) return false;
ListNode slow = head; //准备一个慢指针
ListNode fast = head.next; //准备一个快指针
while (fast != null && fast.next != null) {
//当快指针不为空,或者快指针的下一步不为空
/*
为什么这样设置循环条件fast.next != null???
因为快指针每次都走两次,如果快指针下一步为空,没有走的必要了,因为假设此时快指针继续走一步,
就会变成null,也就是说fast.next = null,由于每次快指针是走两步的,也就是意味着,快指针还得继续走多一步,那么会继续执行fast.next,但是由于上一个的fast.next已经变成null,这里调用next会出现空指针异常。
*/
slow = slow.next; //慢指针每次走一步
fast = fast.next.next; //快指针每次走两步
if (slow == fast) return true; //当慢快指针相遇,说明就是有环的
}
//代码执行到这里,说明快指针已经走完了,慢指针没有机会遇到快指针了
return false;
}
}
彩蛋:
实际上,快慢指针还可以用来寻找一条链表的中间节点,其中核心思想就是,链表的节点个数无非就是三种情况,要么0个,不然就是奇数个或者偶数个,我在代码中详细注释举例了三种情况。
题目链接:876. 链表的中间结点
解析+代码:
class Solution {
/*
双指针思想,慢指针slow一次走一步,快指针fast一次走两步,当快指针走完的时候,慢指针一定在链表的中间位置
为什么呢?
因为链表个数无论如何不是奇数就是偶数,要么就是0个,那么也就是说,只存在三种情况
假如是奇数,1->2->3->4->5
第一次,slow = 2,fast = 3
第二次,slow = 3,fast = 5,此时fast.next == null 所以遍历结束,slow的确是中间节点
假如是偶数,1->2->3->4->5->6
第一次,slow = 2,fast = 3
第二次,slow = 3,fast = 5
第三次,slow = 4,fast = null,此时fast = null 所以遍历结束,slow的确是中间节点
*/
public ListNode middleNode(ListNode head) {
//准备快慢指针
ListNode slow = head, fast = head;
while(fast != null && fast.next != null){
/*
这里的fast.next != null和fast != null
是为了防止下面的fast.next.next出现空指针异常
*/
slow = slow.next; //走一步
fast = fast.next.next; //走两步
}
return slow;
}
}
都看到这里了,不考虑点个赞再走嘛!
以上是关于一个浪漫的算法(快慢指针)的主要内容,如果未能解决你的问题,请参考以下文章