1. 程式人生 > 其它 >二分查詢筆記

二分查詢筆記

技術標籤:Leetcode

參考文章
詳解二分查詢演算法
ps. 這篇文章細節解釋得非常好。

相關習題
尋找一個數:https://leetcode-cn.com/problems/binary-search/
尋找左右邊界:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/

核心思想

  • 查詢的區間為[left,right] 或者 [left,right) 。兩種方式皆可,但注意程式碼前後的統一性。本篇筆記只使用[left,right]的區間表示方式
  • 迴圈的停止條件為搜尋區間為空
    (1) 當查詢區間為[left,right]時,迴圈為while(left<=right){...},迴圈結束時left == right+1
    (2) 當查詢區間為[left,right)時,迴圈為while(left<right){...},迴圈結束時有left == right。
  • 使用mid切分陣列。
    (1) 使用[left,right]時,分割後的陣列為[left,mid-1] 和 [mid+1,right],所以更新時left=mid+1,right=mid-1
    (2) 使用[left,right)時,分割後的陣列為[left,mid) 和 [mid+1,right),所以更新時left=mid+1,right=mid
  • 注意事項:使用 int mid=left+(right-left)/2; 防止溢位(養成習慣!)

尋找一個數

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0, right=nums.size()-1;//區間為[left,right]
        while(left<=right){  //迴圈前提條件:保證搜尋區間不為空,==時仍有元素
            int mid=left+(right-left)/2;//防止溢位
            if
(nums[mid]==target) return mid; else if(nums[mid]<target) left=mid+1;//[mid+1,right] else right=mid-1;//[left,mid-1] } return -1; } };

尋找左邊界

迴圈結束時,left表示陣列中第一個nums[i]>=target的索引,其中0<=left<=nums.size()

因此,迴圈結束後需要

  • 判斷 left==nums.size()
  • 根據nums[left]==target判斷target是否存在。
class Solution {
public:
    int searchRange(vector<int>& nums, int target) {
        int n=nums.size();
        //尋找左邊界
        int left=0, right=n-1;//[left,right]
        while(left<=right){  //迴圈條件:搜尋的區間不為空
            int mid=(right-left)/2+left;//將陣列拆分成[left,mid-1]和[mid+1,right]
            if(nums[mid]>=target)
                right=mid-1;
            else 
                left=mid+1;
        }
        //迴圈結束時left==right+1。其中left為第一個滿足nums[i]>=target的索引,0<=left<=n,需要判斷nums[left]是否為所求
        if(left==n || nums[left]!=target)
            return -1;
        return left;
    }
};

尋找右邊界

迴圈結束時,left表示陣列中第一個nums[i]>target的索引,其中0<=left<=nums.size(),需要判斷left-1是否為要尋找的target。

因此,迴圈結束後需要

  • 判斷 left==0
  • 根據 nums[left-1]==target 判斷target是否存在。
class Solution {
public:
    int searchRange(vector<int>& nums, int target) {
        int n=nums.size();
        //尋找右邊界
        int left=0, right=n-1;//[left,right]
        while(left<=right){
            int mid=(right-left)/2+left;//迴圈條件:搜尋的區間不為空
            if(nums[mid]<=target)
                left=mid+1;
            else
                right=mid-1;
        }
        //迴圈結束時left==right+1。其中left為第一個滿足nums[i]>target的索引,0<=left<=n,需要判斷nums[left-1]是否為所求
        if(left==0 || nums[left-1]!=target)
            return -1;
        return left-1;
    }
};