链表中环的入口节点-23
给定一个链表,若其中包含环,则输出环的入口节点。
若其中不包含环,则输出null
。
样例
给定如上所示的链表:
[1, 2, 3, 4, 5, 6]
2
注意,这里的2表示编号是2的节点,节点编号从0开始。所以编号是2的节点就是val等于3的节点。
则输出环的入口节点3.
思路:
阶段 1:
这里我们初始化两个指针 - 快指针和慢指针。我们每次移动慢指针一步、快指针两步,直到快指针无法继续往前移动。如果在某次移动后,快慢指针指向了同一个节点,我们就返回它。否则,我们继续,直到 while 循环终止且没有返回任何节点,这种情况说明没有成环,我们返回 null 。
阶段 2:
给定阶段 1 找到的相遇点,阶段 2 将找到环的入口。首先我们初始化额外的两个指针: ptr1 ,指向链表的头, ptr2 指向相遇点。然后,我们每次将它们往前移动一步,直到它们相遇,它们相遇的点就是环的入口,返回这个节点。
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head == null || head.next == null) return null;
ListNode node = getInsert(head);
if(node == null) return null;
ListNode p1 = head;
ListNode p2 = node;
while(p1 != p2){
p1 = p1.next;
p2 = p2.next;
}
return p1;
}
public ListNode getInsert(ListNode head){
ListNode slow = head;
ListNode fast = head;
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
if(slow == fast) return slow;
}
return null;
}
}
使用 Set:
时间和空间复杂度均为 O (n)
public class Solution {
public ListNode detectCycle(ListNode head) {
Set<ListNode> visited = new HashSet<ListNode>();
ListNode node = head;
while (node != null) {
if (visited.contains(node)) return node;
visited.add(node);
node = node.next;
}
return null;
}
}