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

二分查找算法简介

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

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

相关推荐
soldierluo2 小时前
向量与向量数据
人工智能·算法·机器学习
a努力。2 小时前
字节跳动Java面试被问:一致性哈希的虚拟节点和数据迁移
java·开发语言·分布式·算法·缓存·面试·哈希算法
VT.馒头2 小时前
【力扣】2622. 有时间限制的缓存
javascript·算法·leetcode·缓存·typescript
Hcoco_me2 小时前
大模型面试题71: DPO有什么缺点?后续对DPO算法有哪些改进?
人工智能·深度学习·算法·自然语言处理·transformer·vllm
mit6.8242 小时前
dfs|bfs建图|hash贪心
算法
罗湖老棍子3 小时前
团伙(group)(信息学奥赛一本通- P1385)
算法·图论·并查集
Ka1Yan3 小时前
[链表] - 代码随想录 160. 相交链表
算法·leetcode·链表
学嵌入式的小杨同学3 小时前
C 语言实战:动态规划求解最长公共子串(连续),附完整实现与优化
数据结构·c++·算法·unity·游戏引擎·代理模式
rgeshfgreh3 小时前
顺序表实战:构建到销毁全解析
算法