I.Given a linked list, determine if it has a cycle in it. Can you solve it without using extra space?
/** Definition for singly-linked list.*/
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
public class Getout { //342ms
<span style="white-space:pre"> </span>public boolean hasCycle(ListNode head) {
<span style="white-space:pre"> </span>if (head == null || head.next == null){
<span style="white-space:pre"> </span>return false;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>ListNode p = head, q = head;
<span style="white-space:pre"> </span>while ((q.next != null) && (q.next.next != null)){
<span style="white-space:pre"> </span>p = p.next; //p每走一步,q要走两步,如果有环,q总会追到p
<span style="white-space:pre"> </span>q = q.next.next;
<span style="white-space:pre"> </span>if (p == q){
<span style="white-space:pre"> </span>return true;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return false;
}
}
II.Given a linked list, return the node where the cycle begins. If there is no cycle, return null
.Can you solve it without using extra space?
通过I可以确定链表是否有环,并且可以找到在环上相遇的节点。那么在此基础上,该如何找到环入口呢?我们假设链表总长为l,环的总长为r,head到环入口的距离为a,则l = a + r,环入口到相遇节点的距离为x,那么显然p节点行走的距离s = a + x (1),而q是p行走距离的两倍(因为p每走一步,q走两步),而且q能追上p,是因为q比p在环内多走了n圈,所以2s = a + x + nr (2),由(1)(2)可以得到,
a + x = nr ==> a + x = (n - 1)r + l - a ==> a = (n - 1)r + ( l - a - x )
(l - a - x)为相遇点绕环到环入口点的距离 ,由此可知,从head到环入口点的距离a就等于(n-1)次环循环加上相遇点到环入口点,所以我们可以设置两个指针p,q,分别从head和meet处同步前进,当p==q时,则必然为环入口节点。
public class Solution { //316ms
public ListNode detectCycle(ListNode head) {
if (head == null || head.next == null){
return null;
}
ListNode p = head, q = head;
while ((q.next != null) && (q.next.next != null)){
p = p.next;
q = q.next.next;
if (p == q){ //p,q即为meet节点,将p置为head,开始同步遍历,再次相遇即为环入口节点
p = head;
while (p != q){
p = p.next;
q = q.next;
}
return p;
}
}
return null;
}
}