二分法模板——y总

二分法模板——y总

参考链接:二分查找算法模板 - AcWing

二分法:是一种在有序数组中查找给定关系元素的算法。

算法思路:假设目标值在闭区间[left, right]中,每次将区间折半,当lleft==right时,就找到了目标值。

二分法的边界条件令人头痛,

while(left<=right) 还是 while(left<right)

left=mid 还是left=mid+1

y总给出了两个版本的二分法查找模板,用于不同情况,退出条件均为 while(left<right)

版本一

**适用于:**查找有序数组中的左边界。列如:在升序数组中找到第一个不小于target的索引。

nums = [5,7,7,8,8,10], target = 8;
ans = 3;
int bsearch_left(vector<int> &nums, int target)
{
	if (nums.empty()) return -1;

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

上示代码,只有 nums[i] < target 时才会更新 left = mid + 1,那么只会有下图示的两种情况:

  • 若某次 mid 取到了 ① 位置 ,则 left 先于right到达目标位置②,后续只会更新 right,直至 right 指向位置③,在下一次循环中,由于int mid = left + (right - left) / 2; 是向下取整,mid会落在left,更新 right = mid 后 left 和 right 最后都会指向位置②;

在这里插入图片描述

  • 另一种情况就是 mid 未取到了 ① 位置,right 先于 left 到达位置②,后续只会更新 left,直至 left指向位置 ①,在下一次循环中,由于int mid = left + (right - left) / 2; 是向下取整,mid会落在left,更新 left = mid + 1,使 left 也会指向位置②。

在这里插入图片描述

版本二

**适用于:**查找有序数组中的右边界。列如:在升序数组中找到最后一个不大于target的索引。

nums = [5,7,7,8,8,10], target = 8;
ans = 4;
int bsearch_right(vector<int> &nums, int target)
{
	if (nums.empty()) return -1;

	int left = 0, right = nums.size() - 1;
	while (left < right)
	{
		int mid = left + (1 + right - left) / 2; //向上取整
		if (nums[mid] <= target) left = mid;
		else right = mid - 1;
	}
	return left;
}

上示代码,只有 nums[i] > target 时才会更新 right= mid - 1,那么只会有下图示的两种情况:

  • 若某次 mid 取到了 ③ 位置 ,则 right先于left到达目标位置②,后续只会更新 left,直至 left指向位置①,在下一次循环中,由于int mid = left + (1 + right - left) / 2; 是向上取整,mid会落在 right ,更新 left = mid 后 left 和 right 最后都会指向位置②;

    在这里插入图片描述

  • 另一种情况就是 mid 未取到 ③ 位置,left先于 right到达位置②,后续只会更新 right,直至 right指向位置 ③,在下一次循环中,由于int mid = left + (right - left) / 2; 是向上取整,mid会落在right,更新 right = mid - 1, 使 right 也会指向位置②。

    在这里插入图片描述

案例

34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode) (leetcode-cn.com)

在这里插入图片描述

题中,给定一个升序数组,找出目标值在数组中的开始位置和结束位置,实质就是找到升序数组中第一个不小于(即大于等于)目标值的索引,和最后一个不大于(即小于等于)目标值的索引。

class Solution {
public:
	vector<int> searchRange(vector<int>& nums, int target) {
		if (nums.empty()) return { -1,-1 };

		vector<int> ans(2, -1);
		int left = 0, right = nums.size() - 1;
		while (left < right)
		{
			int mid = left + (right - left) / 2;
			if (nums[mid] >= target) right = mid;
			else left = mid + 1;
		}
		if (nums[left] != target) return ans; //未找到目标值
		ans[0] = left;

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

		return ans;
	}
};```

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值