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

二分查找算法简介

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中缺失的数字

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

相关推荐
find1star7 小时前
LeetCode 141:环形链表
java·算法·leetcode·链表
迅翼SwiftWing7 小时前
编队系列(总)|固定翼编队如何实现稳定飞行?通信架构、协同算法与工程约束深度解析
算法·架构
LB21127 小时前
力扣160 21 86
算法·leetcode·职场和发展
小智老师PMP9 小时前
2026深度解析|PMP第八版与NPDP核心侧重点本质区别(管理类证书怎么选)
开发语言·分布式·算法·职场和发展·产品经理
HugoStudio_SWAN9 小时前
洛谷 B4450 / B3867 / B3923 智慧购物、储蓄与做题——从程序到生活
c++·学习·程序人生·算法·生活
a187927218319 小时前
【算法】动态规划第二篇:双序列 DP 三课——继承、计步与断链
算法·leetcode·动态规划·dp·回溯·暴力·算法讲解
江畔柳前堤10 小时前
前台·中台·后台:2026年AI原生时代的架构全景图
开发语言·人工智能·算法·机器学习·架构·scala·ai-native
文心快码BaiduComate10 小时前
2026 OPC x AI Coding 趋势案例交流会圆满落幕:一个人就一支研发团队
算法
ACM-moran11 小时前
条件显化(二分单峰函数+构造数列)
算法·推公式·整数三分
闻缺陷则喜何志丹11 小时前
【栈 运算系统】P3719 [AHOI2017初中组] rexp|普及+
c++·算法··洛谷·运算系统