判斷連結串列是否有環---leetcode題目
分享2道leetcode題目(判斷連結串列是否有環以及找出環的入口點)
141. Linked List Cycle
Given a linked list, determine if it has a cycle in it.
142. Linked List Cycle II
Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
第一題就是給你一個連結串列,讓你判斷是否有環,如果有返回true,否則返回false
解法過程
1.首先說明連結串列環的構成:
連結串列的某個節點的next指標指向到前面的節點,如以下所示
(0->1->2->3->4->5->6->3->4…)
這樣子在6節點的後面就會形成無窮無盡的連結串列,就形成環了。
2.設定分別設定一個快慢指標,快指標執行速度是慢指標的2倍,如果該連結串列是個環,則快慢指標必相遇,並且相遇是慢指標並沒有跑完整個連結串列長度
快指標設定fast = fast.next.next;
慢指標設定slow = slow.next;
public boolean hasCycle(ListNode head) {
if (head == null || (head.next == null)) {
return false;
}
ListNode slow = head;
ListNode fast = head;
//如果快慢指標相遇,則存在環
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if(fast == slow) {
return true;
}
}
return false;
}
第二題就是給你一個連結串列,如果這個連結串列有環,則返回環的入口點,如果沒有返回null
解法過程
先列出一個有環的連結串列:
1->2->3->4->5->6->7->8->9->10->3->4…
那答案就是這個連結串列返回3這個節點
1.順著第一步分析,快慢指標相遇點是在9這個節點,如果這時候在9這處放置一個指標,在頭節點處放置一個指標,讓他們同時以相同的速度移動,則很恰巧他們是在3這個環的入口點相遇,這是巧合嗎。接下來就要驗證該方法是否可行。
設定連結串列長度為L,入口點距離頭節點距離為a,快慢指標相遇點距離入口點為b,滿指標速度為s,環的長度為r,則可以得到以下公式:
2s = s + nr (n為環的圈數)
s = a + b (慢指標從頭節點走到相遇點)
r = L - a
2.則我們可以把公式變形成如下
a + b = nr
a = nr -b
a = (n-1)r + r - b
a = (n-1)r + (L -a -b)
這個公式可以得出a就是環入口距離頭節點的距離,(n-1)r是(n-1)圈的環,(L-a-b)其實就是相遇點到環入口的距離
那其實可以得出如果一個指標從相遇點出發,則一定會跟一個從頭指標出發的指標相遇,並且相遇點 就是環的入口點
3.那麼解法就很簡單了
public ListNode detectCycle(ListNode head) {
if(head == null || (head.next == null)) {
return null;
}
ListNode slow = head,fast = head;
ListNode start = head;
ListNode end = null;
//快慢指標找到相遇點
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if(fast == slow) {
end = fast;
break;
}
}
if(end == null || end.next == null ){
return null;
}
//這時重新在相遇點跟head出設定指標,然後同時走一步,則相遇點就是環入口
while(start != end) {
start = start.next;
end = end.next;
}
return start;
}
謝謝欣賞!