闭区间二分搜索 #
二分搜索根据区间的开闭一般有三种写法:左开右闭、左闭右开、闭区间。
熟悉其中一种就够了,下面是闭区间的二分搜索:
int lower_bound(vector<int>& nums, int target){
// 区间为[0, nums.siz()-1],闭区间
int left=0, right=nums.size()-1;
// 当 left<=right 不成立时,[left, right]为空区间,退出循环
while(left <= right){
// 目标在右侧时,更新左区间
if(nums[mid] < target)
left = mid + 1;
// 目标在左侧时,更新右区间
else if(nums[mid] > target)
right = mid - 1;
// 当找到目标值时,持续更新左区间
else
right = mid - 1;
}
return left; // 返回左边界
}
需要了解这个算法在不同条件下的返回值:
当target在数组中存在时,返回它的左边界;
当target小于所有元素时,返回的左边界为0;
当target大于所有元素时,返回的左边界为nums.size();
当上述情况都不满足时,返回大于target的最小元素的左边界!!!(这和第二条相符)
总结来说,这个算法返回的是大于等于target的最小元素的左边界!!!
根据上面的规则,假如要查找一个有序数组中重复元素的左右边界,可以采用如下方式:
int left = 0, right = 0;
left = lower_bound(nums, target);
if(nums[left] == target) // 数组中存在该元素
right = lower_bound(nums, target+1)-1;
else:
printf("不存在该元素")
要计算该元素在数组中出现的次数,可以直接采用right - left + 1
的方式。
这是比较考验微操的算法,得多熟悉一下。
leetcode相关题目: 2529. 正整数和负整数的最大计数 | 275. H 指数 II