数组——二分查找

昨天看了代码随想录Carl哥的数组二分,记录一下自己的思考。

在Carl哥的pdf里,提了两种划分区间。
一种是左闭右闭,即[left, right],对应以下两点:

  • while(left <= right),之所以是<=,而不是<,是因为左闭右闭的情况下,left==right是有意义的;
  • if(arr[mid] > target),r=mid-1,因为接下来要找的区间是[left, mid-1]。

第二种是左闭右开,即[left, right),对应以下两点:

  • while(left < right),<是因为左闭右开的情况下,left不能等于right;
  • if(arr[mid] > target),r=mid,因为接下来要找的区间是[left, mid)。

但是,但是,Carl哥的pdf里的例题比较简单,如果因此忽略这两种方式的代码区别的话,在做题的时候又会一脸迷茫了。
通过比较两种方式的代码,发现:

  1. 左闭右闭,r=mid-1,l=mid+1;
  2. 左闭右开,r=mid, l = mid + 1;

然后,就是做pdf中推荐的leetcode题。
这里,我推荐做 34. 在排序数组中查找元素的第一个和最后一个位置
记录一下我根据这一思想做这道题的思路。

  1. 首先,查找元素的第一和最后一个位置,就是找元素的左右边界,都可以通过二分查找来找到;
  2. 先找左边界:
int start = -1, end = -1;           // 记录左右边界
int l = 0;
int r = nums.length - 1;            // 这里采用左闭右闭方式,[left, right]
int mid = l + (r - l) / 2;
while (l <= r) {                    // 左闭右闭,l <= r
  if (nums[mid] > target) {
       r = mid - 1;                 // 左闭右闭,r = mid - 1
  } else if (nums[mid] < target) {
       l = mid + 1;                 // 左闭右闭,l = mid + 1
  } else {
       r = mid - 1;                 // r = mid - 1,因为要在左边区间[left, mid-1]里寻找
       start = mid;                 // 记录左边界
  }
}
  1. 再找右边界:
l = 0;
r = nums.length - 1;                // 仍然采用左闭右闭的方式
mid = l + (r - l) / 2;
while (l <= r) {                    // 左闭右闭
  if (nums[mid] > target) {
    r = mid - 1;                    // 左闭右闭
  } else if (nums[mid] < target) {
    l = mid + 1;                    // 左闭右闭
  } else {
    l = mid + 1;                    // l = mid + 1,因为要在右区间[mid + 1, right]里找
    end = mid;                      // 记录右边界
  }
}
  1. 结合左右边界,判断返回值:
if (start == -1 || end == -1)    // start、end还是初始值,说明数组中没有等于target的数
  return new int[]{-1, -1};
return new int[]{start, end};

关于左闭右开、左闭右闭两种方式,在做题时都可以采用,在我看来结果上没有区别。
切记注意的是:一经选用某一方式,一定要始终保证区间定义不变!
1. 左闭右闭,r = nums.length - 1,while(l <= r),r = mid - 1,l = mid + 1。
2. 左闭右开,r = nums.length,while(l < r),r = mid,l = mid + 1。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值