「这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战」
题意描述
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:返回索引为 1 的链表节点 解释:链表中有一个环,其尾部连接到第二个节点。
解法1:双指针
思路:主要分两步
-
第一次循环使用快慢指针确认是否为循环链表
-
第二次循环找到循环链表的起始节点,首先假定链表起点到入环的第一个节点A的长度为x,到快慢指针相遇的节点B的长度为(x+y)
分析:假设慢指针走了x + y步,其中x表示从头节点到环入口节点的长度,y 表示从环的入口到相遇节点的位置。快指针走了
x + n*z + y步,其中,n表示快指针已经绕着环走了n次,z表示环的长度。已知,快指针每次走2步,慢指针每次走1步=>2(x + y) = x + nz + y => x = n*z -ypublic class Solution { public ListNode detectCycle(ListNode head) { ListNode slow = head, fast = head; // 是否需要重置 boolean resetFlag = true; while (null != fast && null != fast.next) { slow = slow.next; if (resetFlag) { fast = fast.next.next; } else { fast = fast.next; } if (slow == fast) { if (resetFlag) { slow = head; resetFlag = false; if (slow == fast) { return slow; } } else { return slow; } } } return null; } }
解法2:Set
思路:在解法一的思路上,利用数据结构Set做一些优化
public class Solution {
public ListNode detectCycle(ListNode head) {
Set<ListNode> path=new HashSet<>();
path.add(head);
while (head!=null){
if (path.contains(head.next)){
return head.next;
}
path.add(head);
head=head.next;
}
return null;
}
}