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];
    }
};
相关推荐
飞飞-躺着更舒服9 分钟前
【QT】实现电子飞行显示器(改进版)
开发语言·qt
武昌库里写JAVA25 分钟前
Java成长之路(一)--SpringBoot基础学习--SpringBoot代码测试
java·开发语言·spring boot·学习·课程设计
CYBEREXP200842 分钟前
MacOS M3源代码编译Qt6.8.1
c++·qt·macos
ZSYP-S1 小时前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
yuanbenshidiaos1 小时前
c++------------------函数
开发语言·c++
yuanbenshidiaos1 小时前
C++----------函数的调用机制
java·c++·算法
唐叔在学习1 小时前
【唐叔学算法】第21天:超越比较-计数排序、桶排序与基数排序的Java实践及性能剖析
数据结构·算法·排序算法
程序员_三木1 小时前
Three.js入门-Raycaster鼠标拾取详解与应用
开发语言·javascript·计算机外设·webgl·three.js
是小崔啊1 小时前
开源轮子 - EasyExcel01(核心api)
java·开发语言·开源·excel·阿里巴巴
ALISHENGYA2 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(switch语句)
数据结构·算法