<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          淺談判圈算法

          共 8114字,需瀏覽 17分鐘

           ·

          2022-07-31 00:24

          在計算機科學(xué)中,循環(huán)檢測算法可用于判斷狀態(tài)機中是否存在循環(huán)、鏈表是否存在環(huán)等問題

          abstract.png

          Floyd判圈算法

          判斷是否有環(huán)

          該算法判斷是否存在環(huán)的基本原理是分別使用快、慢指針進(jìn)行遍歷。其中,快指針每次走2步、慢指針每次走1步。如果兩個指針相遇了,則說明存在環(huán);反之,則不存在環(huán)

          計算環(huán)的長度

          當(dāng)存在環(huán)時如何計算環(huán)的長度呢?其實也很簡單。因為判斷是否存在環(huán)的過程中,當(dāng)快、慢指針相遇則說明這兩個指針一定位于環(huán)當(dāng)中了。故此時,只需使用其中任意一個指針按照每次走1步對環(huán)遍歷一圈、進(jìn)行計數(shù)即可

          計算環(huán)的入口

          這里令起始處為A、環(huán)的入口處為B,在判斷是否有環(huán)階段時快慢相遇之處為C。并記AB長度為a、記BC長度為b、環(huán)的長度為r。且在判斷是否有環(huán)過程中,快指針每次走2步、慢指針每次走1步。則快、慢指針相遇時,快指針走過的長度是慢指針走過長度的2倍

          figure 1.jpeg

          此時不難看出,當(dāng)快、慢指針相遇時,快、慢指針走過的長度均是環(huán)長度的整數(shù)倍。故如果期望找到環(huán)的入口位置,即B處。則只需在兩個指針相遇之時,將其中任意一個指針放置到起始處A,而另一個指針依然位于相遇處C。然后兩個指針按照每次均走1步的速度向前走,當(dāng)二者再次相遇之時,即是B處

          原因在于,對于相遇后繼續(xù)往前走的指針而言,由于其已經(jīng)走過了若干圈環(huán)的長度,此時只需再走a步即可到達(dá)環(huán)的入口。這個地方換個角度想會更容易理解,如果該指針先走a步再走若干圈環(huán)的長度,其必然位于環(huán)的入口處;而對于相遇后從起始處A開始走的指針而言,其顯然走a步后,必然也會位于環(huán)的入口處。故此時兩個指針第二次相遇之時,說明他們均已經(jīng)走完a步。即到達(dá)環(huán)的入口處

          Brent判圈算法

          Brent判圈算法相比較于Floyd判圈算法來說,其重點在于提高了判斷是否有環(huán)的時間效率。該算法并沒有解決計算環(huán)的長度、找出環(huán)的入口這兩個問題。具體地,該算法同樣會使用兩個指針:快、慢指針。當(dāng)兩個指針相遇則說明存在環(huán)。具體地,快指針每次始終只會走1步。只不過,第1輪時快指針累計最多只能走2步,第2輪時快指針累計最多只能走4步,第3輪時快指針累計最多只能走8步,以此類推。而慢指針則是在每一輪結(jié)束后,直接移動到快指針的位置處

          實踐

          判斷是否有環(huán)

          學(xué)習(xí)過程中要善于理論聯(lián)系實際。故在介紹完Floyd判圈算法、Brent判圈算法的基本原理后,現(xiàn)在我們來進(jìn)行實踐。這里以LeetCode的第141題——環(huán)形鏈表 為例

          給你一個鏈表的頭節(jié)點head,判斷鏈表中是否有環(huán) 如果鏈表中有某個節(jié)點,可以通過連續(xù)跟蹤next指針再次到達(dá),則鏈表中存在環(huán)。如果鏈表中存在環(huán),則返回 true。否則,返回 false

          示例 1:

          figure 2.png

          輸入:head = [3,2,0,-4] 

          輸出:true

          解釋:鏈表中有一個環(huán),其尾部連接到第二個節(jié)點

          示例 2:

          figure 3.png

          輸入:head = [1,2] 

          輸出:true

          解釋:鏈表中有一個環(huán),其尾部連接到第一個節(jié)點

          示例 3:

          figure 4.png

          輸入:head = [1] 

          輸出:false

          解釋:鏈表中沒有環(huán)

          則基于Floyd判圈算法版本的實現(xiàn)如下所示

          /**
           * Floyd Algo
           */

          public class Solution {
              public boolean hasCycle(ListNode head) {
                  ListNode slow = head;
                  ListNode fast = slow;
                  while ( fast!=null && fast.next!=null ) {
                      slow = slow.next;
                      fast = fast.next.next;
                      if( slow==fast ) {
                          return true;
                      }
                  }
                  return false;
              }
          }

          則基于Brent判圈算法版本的實現(xiàn)如下所示

          /**
           * Brent Algo
           */

          public class Solution {
              public boolean hasCycle(ListNode head) {
                  ListNode slow = head;
                  ListNode fast = slow;
                  // 快指針每輪過程中最多走幾步
                  int limit = 2;
                  // 記錄快指針在每輪過程中走的步數(shù)
                  int step = 0;
                  
                  while ( fast!=null && fast.next!=null ) {
                      // 快指針每次走1步
                      fast = fast.next;
                      step++;

                      // 判斷快、慢指針是否相遇, 即是否存在環(huán)
                      if( fast == slow ) {
                          return true;
                      }

                      // 開啟新一輪的同時, limit變?yōu)樵瓉淼?倍, 同時將慢指針移動到快指針的位置上
                      if( step==limit ) {
                          step = 0;
                          limit = limit * 2;
                          slow = fast;
                      }
                  }

                  return false;
              }
          }

          計算環(huán)的入口

          學(xué)習(xí)過程中要善于理論聯(lián)系實際。故在介紹完Floyd判圈算法、Brent判圈算法的基本原理后,現(xiàn)在我們來進(jìn)行實踐。這里以LeetCode的第141題——環(huán)形鏈表 II 為例

          給定一個鏈表的頭節(jié)點  head ,返回鏈表開始入環(huán)的第一個節(jié)點。 如果鏈表無環(huán),則返回 null。不允許修改鏈表

          示例 1:

          figure 5.png

          輸入:head = [3,2,0,-4] 

          輸出:返回索引為 1 的鏈表節(jié)點 

          解釋:鏈表中有一個環(huán),其尾部連接到第二個節(jié)點

          示例 2:

          figure 6.png

          輸入:head = [1,2] 

          輸出:返回索引為 0 的鏈表節(jié)點 

          解釋:鏈表中有一個環(huán),其尾部連接到第一個節(jié)點

          示例 3:

          figure 7.png

          輸入:head = [1] 

          輸出:返回 null

          解釋:鏈表中沒有環(huán)

          根據(jù)上文對計算環(huán)的入口的說明,不難寫出以下代碼

          public class Solution {
              public ListNode detectCycle(ListNode head) {
                  ListNode entry = null;
                  boolean hasCycle = false;

                  ListNode slow = head;
                  ListNode fast = head;
                  while ( fast!=null && fast.next!=null ) {
                      slow = slow.next;
                      fast = fast.next.next;
                      if( slow==fast ) {
                          // 檢測到環(huán)
                          hasCycle = true;
                          break;
                      }
                  }

                  // 存在環(huán)時, 則計算環(huán)的入口
                  if( hasCycle ) {
                      // 快指針放置到鏈表開始處
                      fast = head;
                      // 快、慢指針每次1步同時移動
                      while ( true ) {
                          // 快、慢指針再次相遇, 即為環(huán)的入口
                          if( fast==slow ) {
                              entry = fast;
                              break;
                          }
                          fast = fast.next;
                          slow = slow.next;
                      }
                  }

                  return entry;
              }
          }


          瀏覽 43
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩在线观看中文字幕 | 做爱网站免费入口观看 | 中文字幕在线字幕中文乱码区别 | 98无码人妻精品一区二区三区 | 乱伦操骚逼视频 |