小白算法積累——單鏈表24#單鏈表+判斷循環

題目:設計一個算法完成以下功能:判斷一個鏈表是否有環,如果有,找出環的入口點並返回。否則返回NULL

關鍵字:單鏈表+判斷循環

思路
關注:
有環的充要條件:兩個指針不停遍歷,一定會相遇

算法的基本設計思想:
1.設置快慢兩個指針分別爲fast和slow,初始時都指向鏈表頭head。
slow每次走一步,即slow=slow->next;
fast每次走兩步,即fast比slow走得快,如果有環,fast一定會先進入環,而slow後進入環。
當兩個指針都進入環後,經過若干次操作後兩個指針定能在環上相遇
這樣就可以判斷一個鏈表是否有環。

如下圖所示,當slow剛進入環時,fast早已進入環。
因爲fast每次比slow多走一步且fast與slow的距離小於環的長度,所以fast與slow相遇時,slow所走的距離不超過環的長度。
在這裏插入圖片描述
如下圖所示,設頭結點到環的入口點的距離爲a, 環的入口點沿着環的方向到相遇點的距離爲x,環長爲r,相遇時fast繞過了n圈。(n=0,1,2,…)(上文已分析,slow走的距離一定等於X,總圈數一定小於等於一圈,不可能出現套圈情況)
相遇時:fast比slow多走的距離爲:n個環長
則有(a+x)/1=(a+nr+x)/2。整理得:a=nr-x
路程/速度=時間
在這裏插入圖片描述
Q:如何將通過數學得到的等式化爲算法呢?
A:回到指針遍歷的實際場景中找尋規律,最終目的是要求返回環的入口點地址。
因此,最理想情況就是當經過一番操作之後,p指針可以剛好降臨在環的入口點,此時返回p指針,就是最終結論。
而到達環的入口點,最常見的起點,即把鏈表第一個結點作爲起點而言,剛好需要行走過a個位置
而數學公式告訴我們:a=n*r-x

顯然:從頭結點到環的入口點的距離
等於
n倍的環長減去環的入口點到相遇點的距離

所以,對於兩個同步指針:
當一個完成從頭結點0~a
可以帶動
另一個完成從環入口點開始,移動n圈還差X個位置,最終到達(在環中)逆時針距離環入口x個位置的任務

讓另另一個完成從環入口點順時針後X個位置開始,完成n圈,最終剛好到達入口點的任務

因此可設置兩個指針,一個指向head,一個指向相遇點(即從環入口點順時針後X個位置),兩個指針同步移動(均爲一次走一步),相遇點即爲環的入口點。

LNode*FindLoopStart(LNode*head){
  LNode *fast=head,*slow=head;//設置快慢兩個指針
  while(slow!=NULL&&fast->next!=NULL){
      slow=slow->next;//慢指針每次走一步
      fast=fast->next->next;//快指針每次走兩步
      if(slow==fast)  break;//相遇
    }
    if(slow==NULL||fast->next==NULL)
       return NULL;//沒有環,返回NULL
    LNode*p1=head,*p2=slow;//確定有環開始找環的入口點。分別指向開始點、相遇點
    while(p1!=p2){
       p1=p1->next;
       p2=p2->next;
    }
    return p1;//返回入口點
  }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章