二分查找模板

二分查找模板

1.base版本(l=mid+1,r=mid-1)

void bin_search(vector<int>& arr,int target){
	int ans=-1;
	int l=0,r=arr.size()-1;
	int mid=l+(r-l)/2;
	while(l<=r){
		mid=l+(r-l)/2;
		if(arr[mid]==target){
			ans=mid;break;
		}else if(arr[mid]>target){
			r=mid-1;
		}else{
			l=mid+1;
		}
	}
	return ans;
}

2.template 1 (left=mid+1;right=mid,mid不加1)

int bin_search(int left, int right) {
  while (left < right) {
    int mid = (left + right) / 2; // 注意防止溢出
    if (check(mid)) // 判断 mid 是否满足查找条件
      left = mid + 1; // 结果落在 [mid+1, right] 区间
    else
      right = mid; // 结果落在 [left, mid] 区间
  }
  return left;
}

3.template 2(left=mid;right=mid-1,mid加1)

int bin_search(int left, int right) {
  while (left < right) {
    // 注意防止溢出
    int mid = (left + right + 1) / 2;
    if (check(mid))
      // 结果落在 [left, mid-1]
      right = mid - 1;
    else
      // 结果落在 [mid, right]
      left = mid;
  }
  return left;
}

两个模板最后都是要收缩到区间   [ l e f t , l e f t + 1 ] \ [left, left+1]  [left,left+1] 里进行最后一次 c h e c k check check
对于模板一,计算得到 m i d = l e f t mid= left mid=left,区间往左收缩是进入 r i g h t = m i d right = mid right=mid ,区间往右收缩是进入 l e f t = m i d + 1 left = mid + 1 left=mid+1,结束循环,所以更新 m i d mid mid 要用 m i d = ( l e f t + r i g h t ) / 2 mid = (left + right)/2 mid=(left+right)/2
对于模板二,计算得到 m i d = r i g h t mid = right mid=right,区间往左收缩是进入 r i g h t = m i d − 1 right = mid - 1 right=mid1 ,区间往右收缩是进入 l e f t = m i d left = mid left=mid,结束循环,所以更新 m i d mid mid要用 m i d = ( l e f t + r i g h t + 1 ) / 2 mid = (left + right + 1)/2 mid=(left+right+1)/2

例1:左边界问题

查找元素 t a r g e t target target的第一个位置,相当于查找 大于等于 t a r g e t target target 的第一个元素位置:
如果 n u m s [ m i d ] < t a r g e t nums[mid] < target nums[mid]<target,此时 t a r g e t target target 应该落在 右半区间 [ m i d + 1 , r i g h t ] [mid+1, right] [mid+1,right]
如果 n u m s [ m i d ] > = t a r g e t nums[mid] >= target nums[mid]>=target,此时 t a r g e t target target应该落在 左半区间 [ l e f t , m i d ] [left, mid] [left,mid],因为 m i d mid mid可能就是 t a r g e t target target,所以还需要进一步比较;
因而选择 c h e c k ( m i d ) check(mid) check(mid) n u m s [ m i d ] < t a r g e t nums[mid] < target nums[mid]<target,区间更新条件分别是 l e f t = m i d + 1 left = mid + 1 left=mid+1; r i g h t = m i d right = mid right=mid;

int searchFirst(vector<int> &nums, int target) {
    int left = 0, right = nums.size() - 1;
    while (left < right) {
      int mid = (left + right) >> 1;
      if (nums[mid] < target)
        left = mid + 1;
      else
        right = mid;
    }
    return nums[left] == target ? left : -1;
  }

例2:右边界问题

查找元素 t a r g e t target target 的最后一个位置,相当于查找 小于等于 t a r g e t target target 的最后一个元素位置:
如果 n u m s [ m i d ] > t a r g e t nums[mid] > target nums[mid]>target,此时 t a r g e t target target 应该落在 左半区间 [ l e f t , m i d − 1 ] [left, mid-1] [left,mid1]
如果 n u m s [ m i d ] < = t a r g e t nums[mid] <= target nums[mid]<=target,此时 t a r g e t target target 应该落在 右半区间 [ m i d , r i g h t ] [mid, right] [mid,right],因为 m i d mid mid可能就是 t a r g e t target target,所以还需要进一步比较
因而选择 c h e c k ( m i d ) check(mid) check(mid) n u m s [ m i d ] > t a r g e t nums[mid] > target nums[mid]>target,区间更新条件分别是 r i g h t = m i d − 1 right = mid-1 right=mid1; l e f t = m i d left = mid left=mid;

int searchLast(vector<int> &nums, int target) {
  int left = 0, right = nums.size() - 1;
  while (left < right) {
    int mid = (left + right + 1) / 2;
    if (nums[mid] <= target)
      left = mid;
    else
      right = mid - 1;
  }
  return nums[left] == target ? left : -1;
}

参考文章:
https://blog.csdn.net/charlsonzhao/article/details/124063879

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值