class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
判断是否有环
set集合法 (时间复杂度O(n), 空间复杂度O(n))
public boolean hasCycle(ListNode head) {
Set<ListNode> set = new HashSet<>();
while (head != null){
if(set.contains(head))
return true;
set.add(head);
head = head.next;
}
return false;
}
快慢指针法(时间复杂度O(n),空间复杂度O(1))
public boolean hasCycle(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
if(slow == fast)
return true;
}
return false;
}
逐个删除法 (时间复杂度O(n),空间复杂度O(1))
public boolean hasCycle(ListNode head) {
ListNode delNode;
while (head != null){
if(head == head.next)
return true;
delNode = head;
head = head.next;
delNode.next = delNode;
}
return false;
}
返回环的入口结点
快慢指针法
- 慢结点 slow 走过的结点数为 a + b
- 快结点 fast 走过的结点数为 a + n * (b + c)
- 由于我们设置慢结点每次走一步,快结点每次走两步,所以有 2 * (a + b) = a + n * (b + c) ,则有 a = (n - 1) * (b + c) + c,所以当两个结点相遇后,我们可以让其中一个节点回到头结点,然后两个结点以相同的速度前进,最终会在环的入口结点相遇
public ListNode detectCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
if(slow == fast){
slow = head;
while (slow != fast){
slow = slow.next;
fast = fast.next;
}
return fast;
}
}
return null;
}
逐个删除法
public ListNode detectCycle(ListNode head) {
while (head != null){
if(head.next == head)
return head;
ListNode temp = head.next;
head.next = head;
head = temp;
}
return null;
}