二分查找详解

二分查找主要是对于一个有序数组的查找,所以在处理之间,需要保证数组的有序,同时在处理的时候,重要的是对于边界的处理,所以在处理上,使用else if的处理会更好一些。

使用二分查找的时候,主要是分为两种,一种是直接得出数据在数组中的位置,还有一种是得到数据的左右边界。

种类一

查找一个数,存在就返回索引位置,不存在的返回-1,这是最熟悉的,也是最基本的。

直接给出解法:

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

注意点:

  • 这里的右边界是nums.length - 1 ,是不会越界的,所以在while循环中是可以取到右边界的。
  • 结束循环的条件是 right ==left
  • 如果右边界变成了 num.length ,那就没法取到,那么在循环中就变了 left<right

种类二

左边界处理

种类一中缺少了对于边界的处理,比如在 数组为[1,1,1,3,4]中 返回数据1在数组中的左边界。

和种类一进行对比,

  1. 种类二在相等的情况下,从相等变成了想左缩小范围,缩小右边界,可以假设在mid的左侧,可能还存在与mid相同的值。
  2. 由于在相等的情况下,会继续执行,那么退出循环的循环条件变成了 left> right ,那么left 就有可能会出现越界的情况,需要进行判断。
  3. 在2中往下思考,会出现退出循环的条件的话,肯定要经历left==tight ,之后经历一次循环之后,就退出循环,那么在最后一次循环后,num[left]可能不等于target,所以需要校验。

解:

int left_bound(int[] nums, int target) {
    int left = 0, right = nums.length - 1;
    // 搜索区间为 [left, right]
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] < target) {
            // 搜索区间变为 [mid+1, right]
            left = mid + 1;
        } else if (nums[mid] > target) {
            // 搜索区间变为 [left, mid-1]
            right = mid - 1;
        } else if (nums[mid] == target) {
            // 收缩右侧边界
            right = mid - 1;
        }
    }
    // 检查出界情况
    if (left >= nums.length || nums[left] != target)
        return -1;
    return left;
}

右边界处理

右边界的处理 和左边界的处理都是对称的,直接给出解

int right_bound(int[] nums, int target) {
    int left = 0, right = nums.length - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid - 1;
        } else if (nums[mid] == target) {
            // 这里改成收缩左侧边界即可
            left = mid + 1;
        }
    }
    // 这里改为检查 right 越界的情况,见下图
    if (right < 0 || nums[right] != target)
        return -1;
    return right;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值