这篇文章写得很好:环检测算法: 弗洛伊德的龟与兔。
我是前段时间做 leetcode 的题,在官方的讲解中看到的,也被称作: Floyd 判圈算法。当时做的那道题就是编写一个函数,传入的链表是否存在环,存在返回 true ,否则返回 false 。
当时做这道题我是利用 js 可以随时给对象加属性的方便来做的,实现思路很简单。 leetcode 环形链表(每日计划) 。我在看到官方使用的龟兔赛跑算法(也称快慢指针)很感兴趣,于是今天打算学习这个算法思路。
先大体说说我的理解: 在大学的操场上跑步的时候,如果你的同学走你跑,基本上每一圈你都会遇到他。那个时候我看到过很多心动的女孩子,有些比我跑得快,有些比我跑得慢,但不管怎样,每次跑步,我都能遇到过多次。
现在再来理解龟兔赛跑算法就很好理解了,之所以能够判定是否是闭环,就看跑得快的能不能遇到跑得慢的。如果跑到了尽头都没遇到“她”,说明不是闭环,否则只要在速度不相同的情况下一定会“相遇”。
这里插一句题外话,其实人生也只是一个环而已。世界上很多都是一个环,之所以在设计的时候设计成环形,就是为了可持续。而人类设计的很多东西不是环形的,或者看似是环形的,其实并不是真正的环,因为要想设计这样的环,一般人都是做不到的。同样也是环才能拯救苦难中的人们。当然任何环都不是永恒的,也就是说每一个环都是有边界的,就像大自然。你会发现当一个人物质世界不丰富的时候往往精神世界特别坚定,因为要想在这个世界上生存,必须要有在面对困难时有一颗能“解决问题的方法论”,有钱的人直接用钱解决,没钱的人通过意念和坚定不移的精神去追求答案。有时候想想,做一切的目的不过是为了心安而已。
跑偏了,只不过环的确很重要。
对于思路已经很清楚,下面使用快慢指针实现它:
const hasCycle = (head) => {
let p, q;
// 首先判定传进来的是否为空,为空直接返回 false
if (!head && !head.next) {
return false;
}
p = head;
q = head.next;
while(p !== q) {
// 判断快指针本身以及下一个节点是否空
if (!q || !q.next) {
return false;
}
p = p.next;
q = q.next.next;
}
// 到这里就是快慢相遇了,说明存在环
return true;
}
其他的概念以后会补齐,比如怎么知道相遇的节点和怎么使用数学公式推到(因为我看了目前还没弄懂)。