算法——有环链表的入口结点
概述
链表存在环,你要找出它的入口结点,能控制空间复杂度为最低吗?言下之意不要用数组、集合这类容器。
思路
- 快慢指针判断有无环
- 记录相遇结点meet
- 慢指针回到head,快指针定位meet,速度都设为1,下次相遇即为入口点。
代码
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode meet = hasCircle(head);
if (meet == null)
return null;
//有环
ListNode p = head,
q = meet;
while (p != q){
p = p.next;
q = q.next;
}
//下次相遇就是环的入口
return p;
}
public ListNode hasCircle(ListNode head){
if (head == null)
return head;
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
//有环,返回相遇点
if (slow == fast)
return fast;
}
//没环,null
return null;
}
}
补充
对于思路中,第3步的推导如下:
链表首:X,环入口:Y,相遇点:Z;
X到Y设为a,Y到Z设为b,Z到Y设为c;
因为Vslow = 1/2 Vfast
所以 2Sslow = Sfast
Sslow = a+b
Sfast = a+n(b+c) + b
推导得出:
a = (n-1)(b+c) + c
注意到b+c即为环长度,所以符合3的推论。