算法训练第一天 | LeetCode 704、LeetCode 27

LeetCode 704

简述题目要求:使用二分查找找到目标值,并且最终返回目标值的下标

思路分析:

对此题来说二分查找有两种形式:①区间是左闭右开    ②区间是左闭右闭

为什么会有这两种形式?

简单讲就是:所取的区间会影响到最终在while循环里面的条件判断,以及当前位置在数组中到底有没有意义,即边界条件。下面接着解析。

首先来解析一下两种形式共同的判断条件:

        很显然有目标值在当前值左边,右边,等于当前值这三种情况

        思路简单,直接上代码

            if(nums[mid]>target){
                //说明在左边
                right = ?;
            } else if (nums[mid]<target) {
                //说明在右边
                left = ?;
            }else {
                return mid;
            }

ok,接下里需要解决的就是?里面到底是什么,这就涉及到二分查找的两种形式,接着分析

①区间是左闭右开

对于左闭右开,说明没有办法取到右区间的端点,既然如此,那么left=right就是没有意义,即不可能的。因此在while里无需加上‘=’

while(left<right){}

while判断完了,接下来就是?到底填什么

对于左闭右开来讲,对于right右指针的初始化是不需要对数组长度-1的,因为根本不会取到

//因为是左闭右开,right不需要-1
int right = nums.length;

 那么对于?的内容也很明朗了,当目标值在当前值左边的时候,我们缩小右区间就不需要再对mid进行-1,理由同上。

//说明在左边,因为是左闭右开,无需-1
right = mid;

当目标值在当前值右边的时候,缩小左区间,此时需要对mid进行+1,进行新区间的判断

//说明在右边
left = mid+1;

 齐活了,附上较完整的代码

    public int search2(int[] nums, int target) {
        int left = 0;
        //因为是左闭右开,right不需要-1
        int right = nums.length;
        //注意终止条件:因为在左闭右开这里,left=right是没有意义的
        while(left<right){
            int mid = (left + right)/2;
            if(nums[mid]>target){
                //说明在左边,因为是左闭右开,无需-1
                right = mid;
            } else if (nums[mid]<target) {
                //说明在右边
                left = mid+1;
            }else {
                return mid;
            }
        }
        //未找到
        return -1;
    }

假如直接拿代码去跑,应该是能通过的,但是,肯定会进坑里了/doge/,别着急,接着往下看

直接拿代码去跑,是可以ac的,但是忽略了一个很重要的问题,就是“溢出”

为什么?

假设left right 为1073741824

加在一起 left+right = 2147483648 超过了int的最大范围 此时就溢出了

因此我们需要再修改一下mid的赋值语句

两种防溢出的方法,挑一个即可
//int mid = left + ((right-left)/2);
//int mid = left + ((right-left)>>1);

 最终代码

    public int search2(int[] nums, int target) {
        int left = 0;
        //因为是左闭右开,right不需要-1
        int right = nums.length;
        //注意终止条件:因为在左闭右开这里,left=right是没有意义的
        while(left<right){
            //防溢出:如果 left 和 right 足够大,mid = (left + right)/2
            //可能会由于 left+right 导致 int 数据类型越界。
            //假设left right 为1073741824
            //加在一起 left+right = 2147483648 超过了int的最大范围 此时就溢出了
            int mid = left + ((right-left)>>1);
            if(nums[mid]>target){
                //说明在左边,因为是左闭右开,无需-1
                right = mid;
            } else if (nums[mid]<target) {
                //说明在右边
                left = mid+1;
            }else {
                return mid;
            }
        }
        //未找到
        return -1;
    }

②区间是左闭右闭

两处不同

第一:左闭右闭的话说明可以取到右端点,因此left=right是有意义的

第二:避免数组越界,要对right进行-1

附上代码

    public int search1(int[] nums, int target) {
        int left = 0;
        int right = nums.length-1;
        while(left<=right){
            int mid = left + ((right-left)/2);
            if(nums[mid]>target){
                right = mid-1;
            } else if (nums[mid]<target) {
                left = mid+1;
            }else {
                return mid;
            }
        }
        return -1;
    }

LeetCode 24

简述题目要求:按照要求原地修改数组

只做了快慢指针版本的

思路分析:

利用两个指针来遍历同一个数组,若nums[fast] == val,那就不更改nums[slow]的值,因为快指针的元素==val后说明这个是需要删除的元素,而!=val的说明是可以保留下来的元素

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值