leetcode 142 环形链表
思路
- 先判断列表是不是空的或者是不是只有一个元素,如果是直接返回null
- 死循环将列表的值逐一加入到hash表中(因为可能是环形的),如果遇到节点是null或者hash表中有值和遍历到的节点值相等,跳出循环,返回当前节点值
public static ListNode detectCycle(ListNode head) {
Set<ListNode> nodeset=new HashSet<>();//创建hash表
if (head==null||head.next==null) return null;//判断是不是空表或者只有一个元素
while (true){
nodeset.add(head);//死循环将节点加入hash表
head=head.next;
if (head==null||nodeset.contains(head))//如果有节点为空(非环形)或者哈希表中有
break;//相同值(环形链表的第一个值),跳出循环
}
return head;
}
今天翻了翻题解,发现了另一种很有趣的解法
双指针法
算法执行步骤
- 定义一个fast指针,每次前进两步,一个slow指针,每次前进一步
- 当两个指针相遇时
2.1. 将fast指针指向链表头部,同时fast指针每次只前进一步
2.2. slow指针继续前进,每次前进一步
当两个指针再次相遇时,当前节点就是环的入口
原理分析
第一次相遇时
慢指针移动的距离为 s1 = A + B + n1 * L
快指针移动的距离为 s2 = A + B + n2 * L
快指针是慢指针速度的两倍,所以 s2 = 2* s1
A + B + n2 * L = 2A + 2B + n1 * L
A = -B + (n2 - n1) * L
因为圆的性质
A = -B + (n2 - n1) * L ===> A = -B
即在第一次相遇点, 向前走A步 ===> 向后走B步
第一次相遇后
快指针从头节点走A步会到达环的入口
慢指针从第一次相遇点走A步,相当于向后走B步,也会到达环的入口
leetcode题解有一个大佬的动图,画的超级好
链接地址