141.判斷連結串列是否有環操作
阿新 • • 發佈:2018-12-09
單鏈表與環的情況
1.判斷連結串列是否有環
對於這個問題我們可以採用“快慢指標”的方法。就是有兩個指標fast和slow,開始的時候兩個指標都指向連結串列頭head,然後在每一步操作中slow向
前走一步即:slow = slow->next,而fast每一步向前兩步即:fast = fast->next->next。
由於fast要比slow移動的快,如果有環,fast一定會先進入環,而slow後進入環。當兩個指標都進入環之後,經過一定步的操作之後 二者一定能夠在環上相遇,並且此時slow還沒有繞環一圈,也就是說一定是在slow走完第一圈之前相遇(肯定是在環上進行相遇)。證明可以看下圖:
public class Solution {
public boolean hasCycle(ListNode head) {
if(head==null) return false;
ListNode walker = head;
ListNode runner = head;
//主要考慮前面的情況吧
//如果是沒有環的情況
while(runner.next!=null && runner.next.next!=null)
{
//如果沒有環的話,逐步減少差距,總會在一個地方相遇到的情況
walker = walker.next;
runner= runner.next.next;
if(walker==runner)
return true;
}
//如果是有環的情況
return false;
}
}
2.判斷一個連結串列是否環,並返回環的開始位置
畫一個圖即可判斷處理, 假設走了K步兩者第一次在環上相遇,此時2K-K=R(R代表環的長度), 所以有K=R假設S代表連結串列起點到環起點的位置,M代表環起點的位置到第一次相遇的地方, R =K=S+M, 所以S = R-M ,當
所以當runner和walker在第一次相遇的時候,讓walker回到起點,讓walker走S, 讓runner走 R-M, 由於s=r-m 兩者會在環起點的位置初相遇,
public class Solution {
public ListNode detectCycle(ListNode head) {
//有環的話必然是兩個以上的節點
if(head==null|| head.next==null) return null;
ListNode walker= head, runner = head;
boolean mark = false;
//判斷是否有環程式碼結構
while(runner.next!=null && runner.next.next!=null){
walker = walker.next;
runner= runner.next.next;
if(runner==walker){
//第一次相遇即可退出
mark = true;
break;
}
}
//沒有環的情況
if(!mark) return null;
//有環的情況下兩者相遇在環上,讓runner停留在第一次相遇的地方
walker = head;
while(walker!=runner){
walker = walker.next;
runner = runner.next;
}
return walker;
}
}