环形链表II和相交链表
环形链表
判断一个链表是否有环,最基本的双指针方法。
1 | public class Solution { |
2 | public boolean hasCycle(ListNode head) { |
3 | //快慢指针 slow每次走1格 fast每次走2格 |
4 | if(head==null) return false; |
5 | ListNode slow = head; |
6 | if(slow.next==null) return false; |
7 | ListNode fast = slow.next.next; |
8 | |
9 | while (fast != null) { |
10 | if (slow == fast) return true; //当快慢指针相遇 说明存在环 |
11 | else { |
12 | slow = slow.next; |
13 | if(fast.next==null) return false; |
14 | fast = fast.next.next; |
15 | } |
16 | } |
17 | //没有环的最终会推出循环 |
18 | return false; |
19 | } |
20 | } |
但是,如果想要判断环形链表中环的起点时,就要考虑快慢指针走了多少次。
假设从链表起点出发到环起点的距离为a
,环的长度为b
,现有快慢指针fast
和slow
第一次相遇。
fast
走的步数是slow
步数的 2倍,即f = 2s
;fast
比slow
多走了 n 个环的长度,即f = s + nb
;( 解析: 双指针都走过a
步,然后在环内绕圈直到重合,重合时fast
比slow
多走环的长度整数倍 )以上两式相减得:
f = 2nb
,s = nb
现在考虑环的起点位置为:a+nb
,所以, slow
指针 位置不变 ,将fast
指针重新 指向链表头部节点 ;slow
和fast
同时每轮向前走 a
步,两个结点再次重合,该节点即为环的起点。
1 | public class Solution { |
2 | public ListNode detectCycle(ListNode head) { |
3 | if (head == null || head.next == null) { |
4 | return null; |
5 | } |
6 | ListNode slow = head, fast = head; |
7 | while (true) { |
8 | slow = slow.next; |
9 | if (fast==null||fast.next == null) { |
10 | return null; |
11 | } else { |
12 | fast = fast.next.next; |
13 | } |
14 | if (slow == fast) break; |
15 | } |
16 | fast = head; |
17 | while (slow != fast) { |
18 | slow = slow.next; |
19 | fast = fast.next; |
20 | } |
21 | return slow; |
22 | } |
23 | } |
相交链表
找到两个单链表相交的起始节点,记链表长度分别为a
和b
,可以考虑fast
结点先走 abs(a-b)
步, 然后fast
和slow
指针在同时往后走直到相交结点。但是获得lenA
和lenB
需要多次遍历链表。
现在考虑如何减少遍历的次数。
设链表A
的长度为a
,链表B
的长度为b
,A
到相交结点的距离为c
,B
到相交节点的距离为d
。
显然可以得到两者相交链表的长度:a - c = b - d
,
变换一下式子得到:a + d = b + c
。
用一个指针从链表A
出发,到末尾后就从B
出发,用另一个指针从B
出发,到末尾后从A
出发,
当前一个指针走了a+d
步数时,后一个指针走了b+c
,两步数相等,即走到了相交节点。
1 | public class Solution { |
2 | public ListNode getIntersectionNode(ListNode headA, ListNode headB) { |
3 | ListNode q = headA, p = headB; |
4 | while (q != p) { |
5 | if (q != null) { |
6 | q = q.next; |
7 | } else { |
8 | q = headB; |
9 | } |
10 | if (p != null) { |
11 | p = p.next; |
12 | } else { |
13 | p = headA; |
14 | } |
15 | } |
16 | return q; |
17 | } |
18 | } |