优选算法【专题三:二分查找算法】

二分查找算法简介

1)二分查找算法的特点:细节最多,最容易写出死循环的算法 但是掌握之后就会变成最简单的算法。

2)学习的侧重点:

1)算法原理

2)模板:不要死记硬背,要理解之后再记忆

有三个模板:

1、朴素的二分模板---- 简单模板--有局限性

2、查找左边界的二分模板----万能--细节

3、查找右边界的二分模板----万能--细节

1、二分查找

https://leetcode.cn/problems/binary-search/submissions/682494476/

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)/2;//不能用这种方法,因为数据量太大时,这样加法会溢出
            //因此,我们要用减法
            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;//上面没找到就不会返回,就返回-1
    }
};

总结:要注意的细节---

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

这个题需要确定区间的左端点和区间的右端点。

我们先来确定区间左端点。

利用二段性,分为两个区间,小于t和大于等于t

核心思想:

确定右端点:

cpp 复制代码
class Solution 
{
public:
    vector<int> searchRange(vector<int>& nums, int target) 
    {
        //处理数组为空的情况--处理越界问题
        if(nums.size() == 0) return {-1,-1};

        int begin = 0;
        //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;
        }
        //经过循环之后,left和right就相遇了,我们需要先来判断一下这个相遇的位置,因为可能是没有目标值的
        if(nums[left] != target) return{-1,-1};//判断相遇位置的值是不是等于目标值,不等于就是没有
        else begin = left;//否则就是等于的,就需要标记左端点
        //2、二分有端点
        left = 0, right = nums.size() -1;
        while(left < right)
        {
            int mid = left + (right - left + 1)/2;
            if(nums[mid] <= target) left = mid;
            else right = mid - 1;
        }
        return {begin, right};
    }
};

模板总结:

3、69.x 的平方根

解法一:暴力解法

从1开始给数平方,直到刚好找到比目标值大的数,那么这个数的前一个数就是要找到的值。

cpp 复制代码
class Solution 
{
public:
    int mySqrt(int x) 
    {
        if(x < 1) return 0;
        int left = 1,right = x;
        while(left < right)
        {
            long long mid = left+(right-left+1)/2; //用int的话两个数相乘就溢出了。
            if(mid*mid <= x) left = mid;
            else right = mid-1; //下面有-1,上面就有+1
        }
        return left;
    }
};

4、35.搜索插入位置

1)我们要找的是等于目标值的。2)我们要找到插入的位置,插入的位置是第一个大于目标值的

因此我们要找的是大于等于target---首先确定是大于等于t而不是小于等于t-----确定等于是属于哪边的,属于小于的一边就left不要移动超过mid(即left=mid**),属于大于的一边,right就移动不要查过mid(即right=mid) ------- 核心!!!**

所以就是

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[right]< target) return right +1;
        return right;
    }
};

目标值比right位置的大,就是要在他的后面,即right+1,目标值比他小,就是要在这个位置(比这个位置前面的大)

能使用二分算法的时候,有二段性就可以用二分算法。

5、852.山脉数组的峰值索引

这个是用的减法

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

这个是用的加法

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

6、162.寻找峰值

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

7、153.寻找旋转数组的最小值

最后left和right指针相遇的时候,返回的值就是要的值,也就是通过中点找到的值。

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

8、找出0~n-1中缺失的数字

下标相等或不同--找的二段性

相关推荐
乐迪信息30 分钟前
港口船舶逆行怎么管?AI防爆摄像机搭载智能检测算法
大数据·人工智能·深度学习·算法·计算机视觉
Sirens.1 小时前
Java并发锁详解:六类锁策略与 synchronized 底层原理
java·前端·算法
和裕2 小时前
全纸结构重型纸箱能否满足 1 吨以上设备出口熏蒸豁免要求?通关合规性全解析
大数据·运维·网络·人工智能·算法
tangguofeng2 小时前
不带头结点的链队操作集(不含InitFlag)(C语言版)
算法
苏打豆4 小时前
CRISP源码阅读——基于ROS2力矩反馈控制器与速度加速度零空间
c++·线性代数·算法·矩阵·机器人
蛋蛋的就会顺顺的4 小时前
hot100——矩阵
java·数据结构·算法·leetcode·力扣
老歌老听老掉牙4 小时前
麻花钻切屑形态演变的力学机制与临界条件分析
python·算法·钻头
zhangfeng11335 小时前
国产GPU/AI算力芯片现状(修订完整版 · 截至2026年9月
人工智能·算法·ai编程·npu
学代码的CJY5 小时前
从代码出发理解时间复杂度与空间复杂度
数据结构·算法
白帽攻防录5 小时前
SRC 挖洞:WSO2 JWT 算法混淆绕过深度复盘,CVE-2026-5430 不支持的算法怎么变成管理员
网络·算法·安全·网络安全·jwt