<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>

          Go 數(shù)據(jù)結(jié)構(gòu)和算法篇(十):二分查找的變形版本

          共 9816字,需瀏覽 20分鐘

           ·

          2021-04-28 17:26

          日常開發(fā)過程中,除了我們上篇講到的正常的二分查找,還有很多二分查找的變形版本,今天開始,我們就來給大家一一介紹這些變形版本。

          從給定序列中查找第一個(gè)匹配元素

          符合標(biāo)準(zhǔn)的二分查找條件的序列一般是比較理想的情況,如果要查找的元素在序列中有多個(gè)怎么辦?所以我們要給大家介紹的第一個(gè)常見的變形版本,就是在一個(gè)給定排序序列中查找第一個(gè)等于給定值的元素。在繼續(xù)往下看之前,你不妨借機(jī)先思考一下要怎么實(shí)現(xiàn)。

          其實(shí)關(guān)鍵節(jié)點(diǎn)就在于在序列中找到值等于待查找元素值時(shí)的處理。如果此時(shí) mid 位置已經(jīng)到了序列的最左邊,不能再往左了,或者序列中索引小于 mid 的上一個(gè)元素值不等于待查找元素值,那么此時(shí) mid 就是第一個(gè)等于待查找元素值的位置;否則還要繼續(xù)往前找。

          對應(yīng)的 Go 實(shí)現(xiàn)代碼如下,其他地方都一樣,就是 num == nums[mid] 時(shí)的處理邏輯變了:

          package main

          import (
              "fmt"
          )

          // 二分查找變形版本1:查找第一個(gè)值等于給定值的元素
          func binarySearchV1(nums []int, num, low, high int) int {
              if low > high {
                  return -1
              }

              mid := (low + high) / 2
              if num < nums[mid] {
                  return binarySearchV1(nums, num, low, mid - 1)
              } else if num > nums[mid] {
                  return binarySearchV1(nums, num, mid + 1, high)
              } else {
                  // 除了需要判斷第一個(gè)與 num 相等的元素索引外,其他和普通二分查找邏輯一致
                  if mid == 0 || nums[mid-1] != num {
                      return mid
                  } else {
                      return binarySearchV1(nums, num, low, mid - 1)
                  }
              }
          }

          func main() {
              nums := []int{1233456}
              num := 3
              index := binarySearchV1(nums, num, 0len(nums) - 1)
              if index != -1 {
                  fmt.Printf("Find num %d first at index %d\n", num, index)
              } else {
                  fmt.Printf("Num %d not exists in nums\n", num)
              }
          }

          運(yùn)行上述代碼,打印結(jié)果如下:

          從給定序列中查找最后一個(gè)匹配元素

          既然有第一個(gè)等于給定值的查詢,自然就有最后一個(gè)等于給定值的查詢,這就是二分查找的第二個(gè)變形版本:在給定已排序序列中查找最后一個(gè)等于給定值的元素。

          實(shí)現(xiàn)邏輯和上面類似,只需要改動(dòng) num == nums[mid] 時(shí)的處理邏輯,只是這時(shí)的條件變成了 mid 位置到了序列的最右邊,不能再往后了,或者索引大于 mid 的后一個(gè)元素值不等于待查找元素,才返回 mid,否則,還要繼續(xù)往后找。

          下面我來給出查找最后一個(gè)等于給定值的元素的 Go 實(shí)現(xiàn)代碼:

          package main

          import "fmt"

          // 二分查找變形版本2:查找最后一個(gè)值等于給定值的元素
          func binarySearchV2(nums []int, num, low, high int) int {
              if low > high {
                  return -1
              }

              mid := (low + high) / 2
              if num < nums[mid] {
                  return binarySearchV2(nums, num, low, mid - 1)
              } else if num > nums[mid] {
                  return binarySearchV2(nums, num, mid + 1, high)
              } else {
                  // 除了需要判斷最后一個(gè)與 num 相等的元素索引外,其他和普通二分查找邏輯一致
                  if mid == len(nums) - 1 || nums[mid + 1] != num {
                      return mid
                  } else {
                      return binarySearchV2(nums, num, mid + 1, high)
                  }
              }
          }

          func main() {
              nums := []int{1233456}
              num := 3
              index := binarySearchV2(nums, num, 0len(nums) - 1)
              if index != -1 {
                  fmt.Printf("Find num %d last at index %d\n", num, index)
              } else {
                  fmt.Printf("Num %d not exists in nums\n", num)
              }
          }

          運(yùn)行上述代碼,打印結(jié)果如下:

          在給定序列中查找第一個(gè)大于等于給定值的元素

          二分查找的第三個(gè)變形版本是:在給定排序序列中查找第一個(gè)大于等于給定值的元素。

          有了前面的基礎(chǔ),來解決這個(gè)問題,是不是很簡單?所不同的是判斷節(jié)點(diǎn)不一樣了,我們之前的需求都是查找等于給定值,現(xiàn)在變成了大于等于給定值,所以我們要在 nums[mid] >= num 這個(gè)判斷條件上做文章,思路還是和之前兩個(gè)變形版本類似,當(dāng) mid 已經(jīng)是最左邊的元素,或者 mid 的前一個(gè)元素值小于給定查詢值,則 mid 對應(yīng)元素即為滿足條件的元素,否則繼續(xù)往前查找。

          對應(yīng)的 Go 實(shí)現(xiàn)代碼如下:

          package main

          import "fmt"

          // 二分查找變形版本3:查找第一個(gè)大于等于給定值的元素
          func binarySearchV3(nums []int, num, low, high int) int {
              if low > high {
                  return -1
              }

              mid := (low + high) / 2
              if num <= nums[mid] {
                  // 判斷條件變更,找到第一個(gè)大于等于給定值的元素
                  // 最左側(cè)元素值,或者當(dāng)前 mid 位置前一個(gè)元素值小于給定值
                  if mid == 0 || nums[mid-1] < num {
                      return mid
                  } else {
                      return binarySearchV3(nums, num, low, mid-1)
                  }
              } else {
                  return binarySearchV3(nums, num, mid+1, high)
              }
          }

          func main()  {
              nums := []int{1233456}
              num := 3
              index := binarySearchV3(nums, num, 0len(nums) - 1)
              if index != -1 {
                  fmt.Printf("Find first num greater or equal than %d at index %d\n", num, index)
              } else {
                  fmt.Printf("Num %d not exists in nums\n", num)
              }
          }

          運(yùn)行上述代碼,打印結(jié)果如下:

          在給定序列中查找最后一個(gè)小于等于給定值的元素

          與之相對的,還有我們最后要討論的一個(gè)二分查找的變形版本:在給定序列中查找最后一個(gè)小于等于給定值的元素。

          有了前面幾個(gè)變形版本的鋪墊,相信你自己就可以寫出對應(yīng)的實(shí)現(xiàn)代碼了。這次的判斷節(jié)點(diǎn)變成了 nums[mid] <= num,其中 num 是待查找的元素值,當(dāng) mid 已經(jīng)是最后一個(gè)元素索引,或者 mid 的后一個(gè)元素值大于 num 則當(dāng)前 mid 對應(yīng)元素就是要查找的元素,否則要繼續(xù)往后查找。

          對應(yīng)的 Go 實(shí)現(xiàn)代碼如下:

          package main

          import "fmt"

          // 二分查找變形版本4:查找最后一個(gè)小于等于給定值的元素
          func binarySearchV4(nums []int, num, low, high int) int {
              if low > high {
                  return -1
              }

              mid := (low + high) / 2
              if num >= nums[mid] {
                  // 判斷條件變更,找到最后一個(gè)小于等于給定值的元素
                  // 最右側(cè)元素值,或者當(dāng)前 mid 位置后一個(gè)元素值大于給定值
                  if mid == len(nums) - 1 || nums[mid + 1] > num {
                      return mid
                  } else {
                      return binarySearchV4(nums, num, mid + 1, high)
                  }
              } else {
                  return binarySearchV4(nums, num, low, mid - 1)
              }
          }

          func main() {
              nums:= []int{1233456}
              num := 3
              index := binarySearchV4(nums, num, 0len(nums) - 1)
              if index != -1 {
                  fmt.Printf("Find last num less or equal than %d at index %d\n", num, index)
              } else {
                  fmt.Printf("Num %d not exists in nums\n", num)
              }
          }

          運(yùn)行上述代碼,打印結(jié)果如下:

          關(guān)于二分查找及其變形版本,學(xué)院君就簡單介紹到這里,所有教程代碼,可以在 Github 代碼倉庫獲取:nonfu/go-tutorial,接下來,我們將開始介紹常見的字符串匹配算法。

          (本文完)



          推薦閱讀


          福利

          我為大家整理了一份從入門到進(jìn)階的Go學(xué)習(xí)資料禮包,包含學(xué)習(xí)建議:入門看什么,進(jìn)階看什么。關(guān)注公眾號(hào) 「polarisxu」,回復(fù) ebook 獲取;還可以回復(fù)「進(jìn)群」,和數(shù)萬 Gopher 交流學(xué)習(xí)。

          瀏覽 27
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  红桃视频一区二区三区四区五区在线视频 | 在线亚洲免费视频二 | 性欧美7777777 亚洲成人无码免费观看 | 成人鸡巴视频 | 天堂操逼网 |