力扣:二分查找法和一些注意事项

题目描述:在这里插入图片描述

解题

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

问题:

在二分查找中,通常遇到的两个问题:

  1. while 循环的条件?
    a. left <= right ?
    b. left < right?
  2. right 每次移动的位置?
    a. right = mid - 1?
    b. right = mid?

以上两个问题的关键点就在于我们对于数组操作时,所选择的查询区间,一般分为两种:
3. 左闭右闭 ->> [ ] 表示从最左边到最右边的区间查找,例如[1, 3] 就是 1,2,3
4. 左闭右开 ->> [ )表示从最左边到最右边 - 1的区间查找,例如[1,3)就是1,2

解决

以上两个问题的关键点就在于我们对于数组操作时,所选择的查询区间,一般分为两种:

  1. 左闭右闭 ->> [ ] 表示从最左边到最右边的区间查找,例如[1, 3] 就是 1,2,3
  2. 左闭右开 ->> [ )表示从最左边到最右边 - 1的区间查找,例如[1,3)就是1,2

所以首先确定好自己所选取的区间就可以解决上述两个问题了:

  1. 左闭右闭,这说明我们需要查询的数据就是包含在这个范围里面的,不在范围里面的都不满足条件查询,比如 [1,3],就表示从1查到3。
    a. 这样第一个问题就可以解决了,我们可以举例子来说明,如果最后就剩了一个3,那么区间表示[3,3]符合我们上面的定义,在区间内的都需要查询。所以应该是 left <= right
    b. 第二个问题也是同样的意思,当我们比较的是如果target < nums[mid]才需要对 right 赋值,那么这时其实已经对 mid 这个位置进行了比较,其实已经不满足我们的条件了,并不应该出现在我们的查询范围中,所以应该是 right = mid - 1,这样[left,right] 还是满足左闭右闭,在整个区间内都进行查询
  2. 左闭右开,这说明我们需要查询的数据其实是从左边开始到右边的数字 - 1的范围,并不包含最右边的数字。比如[1,3),就表示从 1 查到 2。
    a. 这样第一个问题就说明:当我们同样剩最后一个数字三的时候,区间表示[3,3)这并不符合我们区间的定义,既要查3,但是又不应该查3。所以我们应该是不能让left = right,所以应该是 left < right
    b. 同样的第二个问题,这时候发现 mid 索引的位置其实已经不满足条件了,但是 mid - 1 的还没有检查,所以我们需要包含 mid - 1 的位置,这时我们就应该让 right = mid这样也是符合我们的区间定义[left, right)但是不包含right

这样我们就解决了二分查找一些不确定的问题。

补充

如果选择左闭右开的区间去进行查询的话,那么 right 的起始位置应该是 num.length 而不是 num.length - 1。就是因为我们查询的时候并不包含最右边的这个数字。

代码

左闭右闭

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

左闭右开

class Solution {
    public int search(int[] nums, int target) {
        int left = 0;
        int right = nums.length;
        while(left < right){
            int mid = (left + right) / 2;
            if(target > nums[mid]){
                left = mid + 1;
            }else if(target < nums[mid]){
                right = mid;
            }else {
                return mid;
            }
        }
        return -1;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值