解法1:边遍历边删除(边标记)
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead) {
if (pHead == null || pHead.next == null) {
return null;
}
if (pHead.next == pHead) {
return pHead;
}
ListNode next = pHead.next;
pHead.next = pHead;
return EntryNodeOfLoop(next);
}
}
删除就是说让这个节点的next指向这个节点本身,当然也可以用其他的方法来做标记
如果遍历到某个节点,发现它已经被删除了,那就是环的第一个节点
时间复杂度O(n)
空间复杂度O(1)
解法2:哈希表
不考虑空间复杂度的情况下可以用这个
import java.util.*;
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead) {
if (pHead == null || pHead.next == null) {
return null;
}
Set<ListNode> visited = new HashSet<ListNode>();
while (pHead != null) {
if (visited.contains(pHead)) {
return pHead;
}
visited.add(pHead);
pHead = pHead.next;
}
return null;
}
}
时间复杂度O(n)
空间复杂度O(n)
解法3:快慢指针
思路:
快指针fast一次走2步,慢指针slow一次走一步,快慢指针相遇时说明有环的存在。
假设在环外有a个节点,在环内走了b个节点, 慢指针还有c个节点没有走
那么相遇的时候,快指针走了a+b+c+b, 慢走了a+b
因为快指针走的是慢指针的两倍,所以a + b + c + b =2 (a + b) = a + b + a + b,也就是c = a;
慢指针再走c步就能到环的入口,也就是再走a步即可;
让快指向头节点,再重新一步一步走,当快指针和慢指针相遇的时候,慢指针走了a步,也正好到入口节点
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead) {
if (pHead == null || pHead.next == null) {
return null;
}
ListNode slow = pHead.next;
ListNode fast = pHead.next.next;
while (fast != null && slow != fast) {
slow = slow.next;
if (fast.next != null) {
fast = fast.next.next;
} else {
return null;
}
}
if (fast == slow ) {
fast = pHead;
while (fast != slow) {
fast = fast.next;
slow = slow.next;
}
}
return fast;
}
}

京公网安备 11010502036488号