二分法经典疑惑--------右开右不开区别

发布时间:2023年12月31日

今天想做一个50天寒假计划,用来激励和督促自己每天都要学点什么。

内容大概就是算法和数据结构,后面希望有时间也学习一下TCP/IP协议,里面的socket编程我一直很有兴趣。

第一天 二分法彻底掌握

题目来源

704. 二分查找 - 力扣(LeetCode)

先抛开题目来说,二分法你一想到第一反应绝对就是简单,为什么呀?字如其名,二分法二分法,就是把一段数据一分为二,进行高效率的搜索查找。是的,没有任何问题,但是如果让你细说呢,涉及到边界条件很容易写错,。例如到底是?while(left < right)?还是?while(left <= right),到底是right = middle呢,还是要right = middle - 1呢?? 原因就在于根本不理解区间的定义!

二分法区间的定义就是不变量? 有两种定义法 左闭右闭? 左闭右开

第一种写法,我们定义 target 是在一个在左闭右闭的区间里,也就是[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){
                right=middle-1;//右界大于  所以不能等于 得减去一
            }else if(nums[middle]<target){
                left=middle+1;
            }else{
                return middle;
            }
        }
        return -1;//题目要求
    }
};

如果说定义 target 是在一个在左闭右开的区间里,也就是[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(); // 定义target在左闭右开的区间里,即:[left, right)
        while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
            int middle = left + ((right - left) >> 1);
            if (nums[middle] > target) {
                right = middle; // target 在左区间,在[left, middle)中
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,在[middle + 1, right)中
            } else { // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};

记住无效的空间 举个例子? 第一种写法[1,1]合法,表示集合有一个元素。而第二种[1,1)不合法,什么都表示不了。所以才有了一二写法的区别

while(left<right)
{
}
和

right=middle;

文章来源:https://blog.csdn.net/weixin_61847358/article/details/135306702
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。