20191216——第三十五题 搜索插入位置

第一个想到的方法肯定是暴力破解法

class Solution {
    public int searchInsert(int[] nums, int target) {
        for(int i =0;i < nums.length;i++){
            if(nums[i]>= target){
                return i;
            }
        }
        return nums.length;
    }
}

第二个方法对于排序数组,立马想到了二分查找

那么聊一聊二分查找
传统的二分查找

取中位数的索引

int mid = (left + right)/2

其实这行代码是有问题的,在left和right都比较大的时候,left+right很有可能超过int类型能表示的最大值,整数溢出

int mid = left + (right - left)/2
更好的写法是:

int mid = (left+right)>>>1;

循环的条件是,while(left <= right)时,再退出循环的时候,需要考虑返回left还是right
在这里插入图片描述

当把二分查找法的循环可以进行的条件写成 while (left <= right) 时,在写最后一句 return 的时候,如果不假思索,把左边界 left 返回回去,虽然写对了,但可以思考一下为什么不返回右边界 right 呢?

2、但是事实上,返回 left 是有一定道理的,如果题目换一种问法,你可能就要返回右边界 right,这句话不太理解没有关系,我也不打算讲得很清楚(在上面代码的注释中我已经解释了原因),因为实在太绕了,这不是我要说的重点。

由此,我认为“传统二分查找法模板”使用的痛点在于:

传统二分查找法模板,当退出 while 循环的时候,在返回左边界还是右边界这个问题上,比较容易出错。

那么,是不是可以回避这个问题呢?答案是肯定的,答案就在下面我要介绍的“神奇的”二分查找法模板里。

关于力扣看到的二分查找法模板的基本思想
首先把循环可以进行的条件写成 while(left < right),在退出循环的时候,一定有 left == right 成立,此时返回 left 或者 right 都可以

或许你会问:退出循环的时候还有一个数没有看啊(退出循环之前索引 left 或 索引 right 上的值)?
没有关系,我们就等到退出循环以后来看,甚至经过分析,有时都不用看,就能确定它是目标数值。

(什么时候需要看最后剩下的那个数,什么时候不需要,会在第 5 点介绍。)

更深层次的思想是“夹逼法”或者称为“排除法”。

“神奇的”二分查找法模板的基本思想(特别重要)
“排除法”即:在每一轮循环中排除一半以上的元素,于是在对数级别的时间复杂度内,就可以把区间“夹逼” 只剩下 1 个数,而这个数是不是我们要找的数,单独做一次判断就可以了。

“夹逼法”或者“排除法”是二分查找算法的基本思想,“二分”是手段,在目标元素不确定的情况下,“二分” 也是“最大熵原理”告诉我们的选择。

还是 LeetCode 第 35 题,下面给出使用 while (left < right) 模板写法的 2 段参考代码,以下代码的细节部分在后文中会讲到,因此一些地方不太明白没有关系,暂时跳过即可。

(right - left) 不加 11 选左中位数,加 11 选右中位数。

class Solution {
    public int searchInsert(int[] nums, int target) {
        int len = nums.length;
        if(nums[len-1]< target){
            return len;
        }
        int left = 0;
        int right = len -1;

        while(left <= right){
            int mid =(right + left)/2;
            //如果等于,直接返回
            if(nums[mid] == target){
                return mid;
            }else if(nums[mid] < target){
                left = mid + 1;
            }else{
                right = mid -1;
            }
        }
        return left;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值