网址: www.nowcoder.com/practice/70…
描述
给定一个长度为 n 的非降序数组和一个非负数整数 k ,要求统计 k 在数组中出现的次数
数据范围:0 \le n \le 1000 , 0 \le k \le 1000≤n≤1000,0≤k≤100,数组中每个元素的值满足 0 \le val \le 1000≤val≤100
要求:空间复杂度 O(1)O(1),时间复杂度 O(logn)O(logn)
public:
int GetNumberOfK(vector<int> data ,int k) {
int l=data.size();
int left=0; //左界
int right=l-1; //右界
int f=(left+right)/2; //判断中项
int ans=0;
for(;right>=left;) //要始终保证左界小于右界,可以相等
{
if(data[f]>=k && (f==0 || data[f-1]<k)) //找到第一个大于等于k的数
{
if(data[f]==k) //如果相等就说明存在,开始打印后续数字
{
for(int i=f;data[i]==k;i++)
{
ans++;
}
return ans;
}
else return 0; //否则说明不存在次数
}
else if(data[f]>=k)
{
right=f-1; //大了,就把中项-1作为右界,范围变成[left,f-1]
f=(left+right)/2;
}
else {
left=f+1; //小了,就把中项+1作为左界,范围变成[f+1,right]
f=(left+right)/2;
}
}
return 0;
}
};
总结:
利用二分法,主要是确定好范围,左右界都是闭区间,每次的数字[i]不符合要查找的数时,说明[i]这个数字不合格,可以排除,就将f进行+1或者-1作为左界或者右界。循环的判断条件是始终保持左界在右界的左面,或者重合。
函数:
c++中有利用[二分查找]的方法在一个排好序的数组中进行查找的函数:lower_bound( )和upper_bound( ),函数定义在<algorithm>头文件中。
lower_bound( begin,end,num):从数组的begin位置到end-1位置之间,二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end地址。用返回的地址减去起始地址begin,可以得到找到的数字在数组中的下标。
upper_bound( begin,end,num):从数组的begin位置到end-1位置,二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end地址。用返回的地址减去起始地址begin,可以得到找到的数字在数组中的下标。
在此题中的运用:
return upper_bound(nums.begin(), nums.end(), target) - lower_bound(nums.begin(), nums.end(), target);
拓展:
在从大到小的排序数组中,重载lower_bound()和upper_bound():
lower_bound( begin,end,num,greater() ):从数组的begin位置到end-1位置二分查找第一个小于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
upper_bound( begin,end,num,greater() ):从数组的begin位置到end-1位置二分查找第一个小于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。