二分查找笔记

参考文章
详解二分查找算法
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;
    }
};

拓展

二分查找的应用:除了寻找target左右边界的基本题型外,许多应用将二分查找和其他知识点包装在一起,这类问题的常见问法为寻找满足某条件的最小值/最大值。二分查找未必是这类题的最优解法,但不失为一种思想。

例1:https://leetcode-cn.com/problems/first-bad-version/
在这里插入图片描述
例2:https://leetcode-cn.com/problems/sqrtx/
在这里插入图片描述

例3:https://leetcode-cn.com/problems/split-array-largest-sum/
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值