C++实现二分查找

目录

例1

例2

例3

例4

例5

例6


例1

704. 二分查找

注意:

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

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

参考代码

cpp 复制代码
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比较,来判断有没有这个值

参考代码

cpp 复制代码
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了,最后一个位置返回不了

参考代码

cpp 复制代码
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;这么写就不对,这是结果强转,要先强转里面的

参考代码

cpp 复制代码
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一直在下坡段

右偏参考代码

cpp 复制代码
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;
    }
};

左偏参考代码

cpp 复制代码
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]比较的参考代码

cpp 复制代码
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种情况

cpp 复制代码
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];
    }
};
相关推荐
傻啦嘿哟8 小时前
构建命令行单词记忆工具:JSON词库与复习算法的完美结合
算法·json
mjhcsp8 小时前
一种新的LCA算法
算法
wen__xvn8 小时前
代码随想录算法训练营DAY24第七章 回溯算法part03
算法·深度优先
无尽的罚坐人生8 小时前
hot 100 560.和为 K 的子数组
数据结构·算法·leetcode
阿蒙Amon8 小时前
C#每日面试题-索引器和迭代器的区别
开发语言·windows·c#
Ll13045252988 小时前
leetcode代码随想录数组篇
数据结构·算法·leetcode
vortex58 小时前
php-fpm + nginx 环境搭建配置与常见问题解决
开发语言·nginx·php
赤狐先生8 小时前
第三步--根据python基础语法完成一个简单的深度学习模拟
开发语言·python·深度学习
一个平凡而乐于分享的小比特8 小时前
ARRAY_SIZE宏作用及使用注意事项
c语言·array_size·内核宏
菜宾8 小时前
java-分布式面试题(事务+锁+消息队列+zookeeper+dubbo+nginx+es)
java·开发语言·分布式