
本文主要介绍以环形链表相关的算法,主要采用Java语言实现,这类算法又称Floyd's Tortoise and Hare Algorithm (Floyd 龟兔赛跑算法),不得不说,这个原理挺神奇的就解决了,环形链表的问题。
注意:以下代码有关链表的算法实现均基于以下链表节点类:
//链表节点类
public class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}龟兔算法动画来自:
Floyd's Hare and Tortoise Algorithm Demo - One Step! Code
相关教程:

如果链表上存在环,那么在环上以不同速度前进的两个指针必定会在某个时刻相遇(如上图所示)。算法分为两个阶段。
存在环情况:(上帝视角)

不存在环情况:(上帝视角)

a.第一次相遇:(证明已经是环)

b.龟回到起点,兔子保持原位不变:

c.再次相遇:再次相遇的位置为环入口

!!!!!!
********精髓之处********
知晓了龟兔算法的精髓后,下来解决这两个经典问题!
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false
示例一:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。示例二:

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。示例三:

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。public boolean hasCycle(ListNode head) {
ListNode h = head; // 兔
ListNode t = head; // 龟
while (h != null && h.next != null) {
t = t.next;
h = h.next.next;
if(h == t){ // 龟兔相遇时,证明是环
return true;
}
}
return false;
}给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
示例一:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。示例二:

输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。示例三:

输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。public ListNode detectCycle(ListNode head) {
ListNode t = head; // 龟
ListNode h = head; // 兔
while (h != null && h.next != null) {
t = t.next;
h = h.next.next;
if (h == t) { //证明是环
t = head; //龟回到起点
while (true) {
if (h == t) { //再次相遇即为环入口
return h;
}
h = h.next; //同时前进
t = t.next; //同时前进
}
}
}
return null;
}本文主要介绍了链表算法中经典问题:龟兔赛跑算法,主要是判断链表中是否有环,以及如何找到环的入口。最重要的是龟兔赛跑算法的两个阶段和背后的原理。并提供了Java代码实现。希望对各位有所帮助,下期见,谢谢~