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

二分查找算法简介

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

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

相关推荐
通信小呆呆3 小时前
电子战抗干扰技术:当“不被干扰”成为一种系统
算法·通信·mimo·isac
笑容掩饰我的失落3 小时前
区块链从小白到精通(八):从零实现一个标准 ERC-20 代币(完整可运行代码)
算法·区块链·php·智能合约·哈希算法
Severus_black3 小时前
【C++初阶】Stack、Queue算法题大练兵!
c语言·c++·算法·stl
2601_967979126 小时前
机器学习必修课:经典算法与Python实战
python·算法·机器学习·实战·课程
程序猿打工仔6 小时前
计算机基础(C语言)考编、专技岗
c语言·开发语言·算法
通信小呆呆7 小时前
电子战干扰技术:从“蛮力压制”到“精准欺骗”,再到“认知博弈”
算法·通信·isac
老师我太想进步了20267 小时前
【数据结构-6】算法美学之单链表(1)
数据结构·算法
希望我万事顺遂8 小时前
力扣hot100-滑动窗口最大值
数据结构·算法·leetcode
꧁细听勿语情꧂8 小时前
二叉树余题,排序、直接插入排序、希尔排序
c语言·开发语言·数据结构·算法
是main不是漫9 小时前
【双指针|LeetCode1089 复写零】巧用逆向思路,破解原地覆盖陷阱
数据结构·算法·leetcode