基本搜尋演算法 二分搜尋法 Binary Search_Leetcode 704

基本搜尋演算法 二分搜尋法 Binary Search_Leetcode 704

更新於 發佈於 閱讀時間約 6 分鐘
raw-image

這題的題目在這:

題目會給我們一個排序好的陣列,還有一個目標值target

要求我們在陣列中尋找target所在的索引位置。
如果target 不存在,返回-1

題目要求必須在O( log n )對數時間內完成 。


測試範例:

Example 1:

Input: nums = [-1,0,3,5,9,12], target = 9
Output: 4
Explanation: 9 exists in nums and its index is 4

Example 2:

Input: nums = [-1,0,3,5,9,12], target = 2
Output: -1
Explanation: 2 does not exist in nums so return -1

約束條件:

Constraints:

  • 1 <= nums.length <= 104
  • -104 < nums[i], target < 104
  • All the integers in nums are unique.
  • nums is sorted in ascending order.

演算法:

其實各家課本或教材都大同小異,都是從剖半找中心點的方式去搜索。

如果中心點 = target,代表已經找到了,就返回中心點。

如果中心點 < target,代表現在的值還太小,就收縮左邊界,往右邊尋找。

如果中心點 > target,代表現在的值還太大,就收縮右邊界,往左邊尋找。

如果最後找不到,就返回-1

但是有幾個小細節要留意:

  1. 中心點尋找時,使用比較安全的計算方式
    中心點 = 左端點 + (右端點-左端點) 除以 2,避免overflow

尤其是靜態型別語言,例如C, C++的同學要特別留意。

mid = left + (right - left ) // 2
  1. 可以額外做一個小優化optimization,當target已經落在搜尋範圍[left, right]之外時,提早終止不必要的搜尋分支
   if not (nums[left] <= target <= nums[right]):
    # optimization, early stop unnecessary branch
    return-1

程式碼:

Iterative method 迭代法:

class Solution:
 def search(self, nums: List[int], target: int) -> int:

  left, right = 0,len(nums)-1

  while left <= right:

   if not (nums[left] <= target <= nums[right]):
    # optimization, early stop unnecessary branch
    return-1

   mid = left + ( right - left ) // 2

   if( nums[mid] == target):
    return mid

   elif nums[mid] < target:
    left = mid+1
   
   else:
    right = mid-1

  return -1

Recursive method 遞迴法:

class Solution:
 def search(self, nums: List[int], target: int) -> int:
  
  def binary_search(nums, left, right, target ):
   
   if left > right:
    # base case:
    # miss
    # target does not exist in input array
    return -1

   if not (nums[left] <= target <= nums[right]):
    # optimization, early stop unnecessary branch
    return -1   

# update index of mid point
   mid = left + (right-left)//2

   if nums[mid] == target:

    # base case:
    # hit
    return mid

   if target > nums[mid]:
    
    # search target in right half
    return binary_search(nums, mid+1, right, target)

   else:

    # search target in left half
    return binary_search(nums, left, mid-1, target)

  #---------------------------
  return binary_search(nums, 0, len(nums)-1, target)

時間複雜度:

O( log n ) , 可以從 T(n) = T(n/2) + O(1) 用Master Theorem推導而來

空間複雜度:

迭代法為O(1),相當於指使用雙指針double pointers,所耗費的空間成本固定,為常數級別O(1)

遞迴法為O( log n),成本來自於recursion call stack depth 遞迴呼叫堆疊深度


Reference:

[1] Python/JS/Go/C++ log( n ) sol. by divide-and-conquer. [ With explanation ] - Binary Search - LeetCode

avatar-img
小松鼠的演算法樂園
95會員
426內容數
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
留言
avatar-img
留言分享你的想法!
題目敘述 Find K-th Smallest Pair Distance 給定一個輸入陣列nums和 參數k。 請找出第k小的pair distance是多少? pair distance定義為 abs( nums[i] - nums[j]), i 不等於j 也就是任意兩陣列元素差值的絕對值
給定一個輸入非負整樹陣列nums,請找出k值,使得陣列中恰好有k個元素大於等於 k。如果無解,回傳-1。尋找k值的方法包括排序法和二分搜尋法,時間複雜度都為O(n log n),空間複雜度為O(1)。關鍵知識點是當解空間具有遞增或遞減的性質時,可以用二分搜尋法加快搜尋效率。
這篇文章,會帶著大家複習以前學過的二分搜尋法(Binary Search)框架, 並且以二分搜尋法的概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個實用的演算法框架。 Binary search 二分搜尋法框架 用途: 在已經排序好的數列中尋找目標值。
題目敘述 Find K-th Smallest Pair Distance 給定一個輸入陣列nums和 參數k。 請找出第k小的pair distance是多少? pair distance定義為 abs( nums[i] - nums[j]), i 不等於j 也就是任意兩陣列元素差值的絕對值
給定一個輸入非負整樹陣列nums,請找出k值,使得陣列中恰好有k個元素大於等於 k。如果無解,回傳-1。尋找k值的方法包括排序法和二分搜尋法,時間複雜度都為O(n log n),空間複雜度為O(1)。關鍵知識點是當解空間具有遞增或遞減的性質時,可以用二分搜尋法加快搜尋效率。
這篇文章,會帶著大家複習以前學過的二分搜尋法(Binary Search)框架, 並且以二分搜尋法的概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個實用的演算法框架。 Binary search 二分搜尋法框架 用途: 在已經排序好的數列中尋找目標值。