二分查找法

一、需查找和目标值相等的数

比如数组 [2, 4, 5, 6, 9],target = 6,返回3,即target 的在数组中的位置。二分查找法的代码如下:

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

注意二分查找法的写法并不唯一,主要可以变动地方有四处:

第一处是 right 的初始化,可以写成 nums.length或者 nums.length- 1。

第二处是 left 和 right 的关系,可以写成 left < right 或者 left <= right。

第三处是更新 right 的赋值,可以写成 right = mid 或者 right = mid - 1。

第四处是最后返回值,可以返回 left,right,或 right - 1。

但是这些不同的写法并不能随机的组合,像博主的那种写法,若 right 初始化为了 nums.length,那么就必须用 left < right,而最后的 right 的赋值必须用 right = mid。但是如果我们 right 初始化为 nums.length - 1,那么就必须用 left <= right,并且right的赋值要写成 right = mid - 1,不然就会出错。

 

二、查找第一个不小于目标值的数

      如果查找的目标值不一定会在数组中出现,也有可能是跟目标值相等的数在数组中并不唯一,而是有多个,那么这种情况下 nums[mid] == target 这条判断语句就没有必要存在。比如在数组 [2, 4, 5, 6, 9] 中查找数字3,就会返回数字4的位置;在数组 [0, 1, 1, 1, 1] 中查找数字1,就会返回第一个数字1的位置,即返回的位置就是 right 指针指向的地方。代码如下:

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

    如果变为查找最后一个小于目标值的数,因为已经找到了第一个不小于目标值的数,那么再往前退一位,返回 right - 1,就是最后一个小于目标值的数。

 

三、 查找第一个大于目标值的数

      这里跟第二种写法上很相似,只需要添加一个等号,将之前的 nums[mid] < target 变成 nums[mid] <= target,这变化其实直接就改变了搜索的方向,使得在数组中有很多跟目标值相同的数字存在的情况下,返回最后一个相同的数字的下一个位置。

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

与第二种一样,可以变形为查找最后一个不大于目标值的数。

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值