题目描述:统计一个数字在排序(非递减)数组中出现的次数。
这道题for循环就能轻松解决,不过这里说一下二分法吧。
解题思路:
① 返回重复元素的左右边界并相减,即可得到指定数字在非递减数组中的出现次数。
② 使用两次二分法,依次算出左边界和右边界的具体数值。
③ 左边界和右边界的获得:当nums[mid] == target
时没有返回mid值,而是收缩区间,从而锁定边界的值。
class Solution {
public:
int search(vector<int>& nums, int target) {
/* 第一次二分:确定重复元素的左边界 */
//定义并初始化循环用左、右边界,观察到为左闭右开区间(nums.size()不可取得)
int l = 0;
int r = nums.size() - 1;
//定义最终版左右边界
int left, right;
//while条件根据区间情况调整,这里由于左闭右开,所以是l<=r
while(l<=r)
{
if(nums[(l+r)/2]==target)
{
//在最简单的二分查找中,找到target就返回当前值,但一般不会这么简单
//收缩右侧边界(动态),以锁定左边界值(静态)
r=(l+r)/2-1;
}else if(nums[(l+r)/2]>target){
//这里没明白为什么要减一,搜索区间变为[l,mid-1]
r=(l+r)/2-1;
}else if(nums[(l+r)/2]<target){
//中值不在闭区间范围内,搜索区间变为[mid+1, r]
l=(l+r)/2+1;
}
}
left=l;
/* 第二次二分:确定重复元素的右边界 */
l = 0;
r = nums.size() - 1;
while(l<=r)
{
if(nums[(l+r)/2]==target)
{
//收缩左侧边界,以锁定右边界值
l=(l+r)/2+1;
}else if(nums[(l+r)/2]>target){
r=(l+r)/2-1;
}else if(nums[(l+r)/2]<target){
l=(l+r)/2+1;
}
}
right=r;
return right-left+1;
}
};