其他分享
首页 > 其他分享> > 关于二分搜索 简单、左侧区间、右侧区间

关于二分搜索 简单、左侧区间、右侧区间

作者:互联网

4月15号阅文一面,问完八股之后被问到了二分搜索,我啪的一下就写出来了,很快啊!面试官也很高兴,想加大一点难度,让我写一下搜索左侧区间的二分搜索。
什么是搜索左侧区间的二分搜索呢?比如一个排序数组里有某个元素重复出现了多次,我们的二分搜索必须每次返回这个元素第一次出现的位置。比如数组 0, 1, 2, 4, 4, 4, 6, 7, 9 输入target = 4 时我们的函数应该返回3
然而啊,我大意了,对这道题的理解还不够深刻,面试的时候写的不对。虽然被面试官指出了问题也改正了,但是面试凉凉了。大家要学好二分搜索啊!不能像我一样。

从最基础的二分搜索谈起

int binSearch(vector<int> &nums, int target){
    int lo = 0, hi = nums.size() - 1; // 将hi设为这个值,意味着搜索期间为闭区间[lo, hi]
    while(lo < hi){ // 因为区间是闭区间,跳出循环的条件是lo < hi 而不是 <=
        int mid = lo + (hi - lo) / 2;
        if(nums[mid] == target){
            return mid;
        }
        else if(nums[mid] < target){ // 中点值比目标值小,说明目标在右侧区间
            lo = mid + 1;
        }
        else if(nums[mid] > target){ // 中点值比目标值大,说明目标在左侧区间
            hi = mid - 1;
        }
        // 小细节:多写几个else if ,而不是直接一个else 这样可以方便对代码的查看和思路的疏通。
    }
    return -1; // 没有找到,返回-1
}

几个比较重要的点已经在注释中标注了,最简单的二分查找在遇到有重复数字的数组时,可能会返回其中符合条件的随机一个位置。因此,如果我们要返回区间左侧或者右侧坐标,需要对其稍稍改变。

返回区间左侧或右侧坐标的二分查找

int findLeft(vector<int>& nums, int target){
    int lo = 0, hi = nums.size() - 1;
    while(lo <= hi){
        int mid = lo + (hi - lo) / 2;
        if(nums[mid] == target)
            hi = mid - 1; //注意
        else if(nums[mid] > target)
            hi = mid - 1;
        else if(nums[mid] < target)
            lo = mid + 1;
    }

    if(lo >= nums.size() || nums[lo] != target) return -1;  //lo可能在合法区间之外(当任意nums[i] < target 均成立时),也可能nums数组中不存在target。
    return lo; 
}

注意,当我们的nums[mid] == target已经成立时,不要直接返回,而是继续收缩区间右侧,令其缩减到目标值出现位置的左侧。我们跳出循环的条件一定是lo == hi - 1, 也就是说,跳出循环时,lo的位置即指向nums[mid] == target 最后一次成立的位置。

搜索右侧区间的算法同理,此处供参考。

int findRight(vector<int>& nums, int target){
    int lo = 0, hi = nums.size() - 1;
    while(lo <= hi){
        int mid = lo + (hi - lo) / 2;
        if(nums[mid] == target)
            lo = mid + 1;
        else if(nums[mid] > target)
            hi = mid - 1;
        else if(nums[mid] < target)
            lo = mid + 1;
    }

    if(hi < 0 || nums[hi] != target) return -1;
    return hi;
}

推荐阅读:labuladong:我写了首诗,让你闭着眼睛也能写对二分搜索
推荐练习: Leetcode 34

标签:二分,target,nums,int,lo,mid,hi,区间,右侧
来源: https://www.cnblogs.com/wstnl/p/16152026.html