二分查找【看了包会】

👉目录

一、 题目连接 704. 二分查找 - 力扣(LeetCode)

二、理论学习-基础二分查找

(1)[left, right] 

(2)[left, right) 

三、基础算法总结

四、lower_bound 、 upper_bound、binary_search (推荐)

五、题目练习


        经过两个月(甚至我觉得更久)的挣扎,终于对基本的算法有了一个稍为全面的理解,理论知识+c++语法的不断练习+刷题背诵模版,但是学到最后对最初的简单算法反而有点淡忘了·····自己是真没学算法的天赋,只能不断一遍遍重复努力了·····

        我的问题(不知道大家会不会有):①接触到新算法后对旧的算法就会忘【可能一开始学的时候就懵懵懂懂的···】②做过的题还是不会做【emm所以我才以博客的形式记录,方便回顾,就像高中数学一样,大量无厘头的刷题不如有一个属于自己的错题本!】③看到新题有思路也能写代码但结果不是报错就是写一半写不下去了【自己静不下心emm再加上语法不熟练 知识点不熟练】

     所以我打算从头开始温习一遍(距离保研机试还有差不多5-6月的时间)加油吧!!😃👍

一、 题目连接 704. 二分查找 - 力扣(LeetCode)

二、理论学习-基础二分查找

        写二分法经常写乱,主要是因为对区间的定义没有想清楚,区间的定义就是不变量。要在二分查找的过程中,保持不变量,就是在while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。

        写二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)

下面我用这两种区间的定义分别讲解两种不同的二分写法。

(1)[left, right] 

因为定义target在[left, right]区间,所以有如下两点:

  • while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=
  • if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0;
        int right=nums.size()-1;//[]
        while(left<=right)
        {
            int middle=(left+right)/2;
            if(nums[middle]<target) left=middle+1;
            else if(nums[middle]>target) right=middle-1;
            else return middle;

        }
        return -1;
        
    }
};

(2)[left, right) 

  • while (left < right),这里使用 < ,因为left == right在区间[left, right)是没有意义的
  • if (nums[middle] > target) right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle]
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0;
        int right=nums.size();//[ )
        while(left<right)
        {
            int middle=(left+right)/2;
            if(nums[middle]<target) left=middle+1;
            else if(nums[middle]>target) right=middle;
            else return middle;

        }
        return -1;
        
    }
};

三、基础算法总结

①先定义left  right  【区间的定义】

②进入循环 【注意循环条件】

③将target 与 nums[middle] 进行比对,结合①对区间的定义 更新左右区间 【主体部分】

四、lower_bound 、 upper_bound、binary_search (推荐)

C++ STL 提供了 lower_boundupper_bound 进行二分查找,它们位于 <algorithm> 头文件中

binary_search() 只能用于已排序的容器 

如何转换为索引?

  • left - nums.begin() 计算 第一个 target 出现的索引

  • right - nums.begin() - 1 计算 最后一个 target 出现的索引

五、题目练习

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
       int res = lower_bound(nums.begin(),nums.end(),target)-nums.begin();
       return res;
    }
};

 

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        vector<int> res = {-1, -1}; // 默认返回 [-1, -1]
        auto left = lower_bound(nums.begin(), nums.end(), target);
        if (left == nums.end()||*left!=target) { 
            //*left 是该迭代器指向的值可能返回一个大于 target 的元素,而不一定是 target
            return res; // target 不存在,直接返回
        }
        
        auto right = upper_bound(nums.begin(), nums.end(), target);
        
        res[0] = left - nums.begin();
        res[1] = right - nums.begin() - 1;

        return res;
    }
};

789. 数的范围 - AcWing题库 

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n,q;
    cin>>n>>q;
    vector<int> nums(n);
    for(int i=0;i<n;i++) cin>>nums[i];
    while(q--)
    {
        int k;
        cin>>k;
        bool have=binary_search(nums.begin(),nums.end(),k);
        if(!have) cout<<"-1 -1"<<endl;
        else//有钙该元素
        {
            int res1=lower_bound(nums.begin(),nums.end(),k)-nums.begin();
            int res2=upper_bound(nums.begin(),nums.end(),k)-nums.begin()-1;
            cout<<res1<<" "<<res2<<endl;
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值