C++实现二分查找

目录

例1

例2

例3

例4

例5

例6


例1

704. 二分查找

 注意:

①left <= right,这里的=号是最后一次通过下标mid来判断

②在偶数的时候mid,左右无所谓,因为left和right都有1;

参考代码

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0, right = nums.size() - 1;
        while(left <= right)
        {
            int mid = left + (right - left) / 2;
            if(nums[mid] < target) left = mid + 1;
            else if(nums[mid] > target) right = mid - 1;
            else return mid;
        }
        return -1;
    }
};

例2

34. 在排序数组中查找元素的第一个和最后一个位置

我把int mid = left + (right - left) / 2;称为左偏

int mid = left + (right - left + 1) / 2;称为右偏

死循环情况如下

如果左偏时,left=mid,那么就不会动了

概括为:左偏left要 + 1,右偏right 要 -1(+-1是相较与mid)

分析:有二段性才可以用二分查找,也就是找二段性

左边段:<target 右边段:>=target

注意这里是left<right,通过出循环时这个位置与target比较,来判断有没有这个值

参考代码

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        if(nums.size() == 0) return {-1, -1};
        int left = 0, right = nums.size() - 1;
        while(left < right)
        {
            int mid = left + (right - left) / 2;
            if(nums[mid] < target) left = mid + 1;
            else right = mid;
        }
        if(nums[left] != target) return {-1, -1};
        int begin = left;
        right = nums.size() - 1;
        while(left < right)
        {
            int mid = left + (right - left + 1) / 2;
            if(nums[mid] > target) right = mid - 1;
            else left = mid;
        }
        return {begin, right};
    }
};

例3

35. 搜索插入位置

这题就是个左偏,

临界点是:>=target,最终left和right是要停在这个位置

为什么会想到最后的if条件? 解释:这是个数组,要返回下标,又往里面插入元素,那么原来的下标范围是[0, nums.size() - 1],那现在个数+1了,最后一个位置返回不了

参考代码

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int left = 0, right = nums.size() - 1;
        while(left < right)
        {
            int mid = left + (right - left) / 2;
            if(nums[mid] < target) left = mid + 1;
            else right = mid;
        }
        if(nums[left] < target) return nums.size();
        return left;
    }
};

例4

69. x 的平方根

解析:临界是<= 那就是右偏,与上面有点不同的是,不是直接拿值比较,多了一步(mid * mid),也没多大差别,条件有点不同,右偏就是left不动,left就是有效值,right之所以-1,因为right所在的位置一定不是,然后再是判断mid是否+1 

注意:这边的溢出mid是int就够的,但是如果right = INT_MAX,left=0,那么括号里面的式子就会溢出,下面的mid*mid也会溢出,还有这里的整形提升是有顺序的,int mid = left + (long long)(right - left + 1) / 2;这么写就不对,这是结果强转,要先强转里面的

参考代码

class Solution {
public:
    int mySqrt(int x) {
        int left = 0, right = x;
        while(left < right)
        {
            int mid = left + ((long long)right - left + 1) / 2;
            if((long long)mid * mid <= x) left = mid;
            else right = mid - 1;
        }
        return left;
    }
};

例5

852. 山脉数组的峰顶索引    162. 寻找峰值这两题代码一样

这题左右偏都可以,找到二段性

这里mid就是有效位置,左偏一定是下标mid和mid-1,这样才能使得left一直在上坡上段,右偏一定是mid和mid+1,使right一直在下坡段

右偏参考代码

class Solution {
public:
    int peakIndexInMountainArray(vector<int>& arr) {
        int left = 0, right = arr.size() - 1;
        while(left < right)
        {
            int mid = left + (right - left + 1) / 2;
            if(arr[mid] > arr[mid - 1]) left = mid;
            else right = mid - 1;
        }
        return left;
    }
};

左偏参考代码

class Solution {
public:
    int peakIndexInMountainArray(vector<int>& arr) {
        int left = 0, right = arr.size() - 1;
        while(left < right)
        {
            int mid = left + (right - left) / 2;
            if(arr[mid] > arr[mid + 1]) right = mid;
            else left = mid + 1;
        }
        return left;
    }
};

例6

153. 寻找旋转排序数组中的最小值

与nums[nums.size() - 1]比较的参考代码

class Solution {
public:
    int findMin(vector<int>& nums) {
        int left = 0, right = nums.size() - 1;
        while(left < right)
        {
            int mid = left + (right - left) / 2;
            if(nums[mid] > nums[nums.size() - 1]) left = mid + 1;
            else right = mid;
        }
        return nums[left];
    }
};

 与nums[0]比较的参考代码,多了的if就是上图的第2种情况

class Solution {
public:
    int findMin(vector<int>& nums) {
        int left = 0, right = nums.size() - 1;
        while(left < right)
        {
            int mid = left + (right - left) / 2;
            if(nums[mid] >= nums[0]) left = mid + 1;
            else right = mid;
        }
        if(nums[nums.size() - 1] > nums[0]) return nums[0];
        return nums[left];
    }
};

  • 44
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值