20200612-判斷連結串列有環
阿新 • • 發佈:2021-01-19
1.1 判斷連結串列有環
這2道題都和判斷連結串列是否有環相關,看下給的例子
Input: head = [3,2,0,-4], pos = 1
Output: true
Explanation: There is a cycle in the linked list, where tail connects to the second node.
對於這樣一個帶環的連結串列,判斷是否有環,最簡單的做法就是遍歷所有的節點,如果遇到重複的節點,則說明有環,由此解法便是,用一個 visitedSet
O(1)
空間複雜度,就有了另外一個思路:
使用一個快指標和一個慢指標來遍歷 list, 如果連結串列有環,則必然存在在某一個節點上2個指標相遇。
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) {
return false;
}
ListNode slow = head;
ListNode fast = head.next;
while (slow != fast) {
if (fast == null || fast.next == null) {
return false;
}
slow = slow.next;
fast = fast.next.next;
}
return true ;
}
如果要找出環的入口位置呢?這裡就涉及一點點數學的上換算了:
假設連結串列 head 到環入口的節點數為 a
(不包含入口節點),環的長度為b
, 慢指標走過的路程為 s
,快指標走過的路程為f
, 當2個指標第一次相遇時,則有如下關係:
- 第一次相遇:
- f = 2s (快指標每次走2步,慢指標每次走1步,所以相遇時路程是 2倍)
- f = s + k*b
這個公式就不太好理解, 假設相遇時的節點距離入口的距離為d, Slow 繞圈為 m, Fast 繞圈為 n, 則:
- s = a + d + m*b;
- f = a + d + n*b;
換算一下就得出,f = (n-m)*b + s; (n>m, 快指標繞圈更多),即 f = s + k * b;
我們將1,2 消一下就得到,s = k * b, 所以說慢指標走了環的 k 圈,若此刻有一個節點從 head 處開始走,它每次路過環入口的時機應該在 a + k * b
(k 為繞圈數),由於慢指標 s=k * b, 所以讓一個節點從頭開始走,當它們相遇時,即為環的入口了。
1.2 反轉連結串列
還有一類經典的連結串列題是反轉連結串列,自己做題的過程中發現要注意的點:
- 如何準確的處理節點之間的關係,先連結後面的關係(先使節點有多個父節點),再修改節點連結
- 知道哪個是 head 節點,比如全部反轉的 list 來說,最後一個節點是新的Head, 對
swap nodes in pairs
來說新的 head 是第2個節點,對reverse nodes in k-gourp
來說,新的 head 是第一組的最後一個節點
- 那麼對於全反轉來說 prev 走到最後一個節點就是新的 Head
ListNode prev=null;
ListNode cur=head;
while(cur != null){
ListNode next = cur.next;
cur.next = prev;
prev = cur;
cur = next;
}
return prev;
- 對於不是最後指標的位置是新 head的,都使用
dummy
來連結新的 Head
ListNode dummy= new ListNode(-1);
dummy.next = head;
mmy` 來連結新的 Head
ListNode dummy= new ListNode(-1);
dummy.next = head;
當 reverse 完畢後, dummy.next
指向新的 head.