数字在升序数组中出现的次数:最直观的想法是,使用一个变量res记录k在数组中出现的次数,初始为0,从头到尾遍历数组,如果当前数组元素等于k,则将res加一,最后返回res即可。注意,由于数组是非降序的,故可以使用剪枝方法,即一旦当前数组元素大于k,则直接break。
int GetNumberOfK(vector<int> data ,int k) {
int res=0;
for(int i=0;i<data.size();i++)
{
if(data[i]>k)
break;
if(data[i]==k)
res++;
}
return res;
}
优化:有序数组当然第一个想到二分法啦!但是一个数组中可能有多个k,故我们若是能够找到k出现的左界和k出现的右界,那么我们即可求出k出现的次数。再者因为数组中全是整数,因此可以考虑二分查找k-0.5和k+0.5应该出现的位置,两者相减即是k出现的次数。因为使用左边界left和右边界right找中点mid时,使用的是向下取整,最后返回的是左边界left,故此方法找到的是k在data中的第一个下标,如果k不存在的话则返回的是第一个大于目标值的下标,因为如果向下取整的mid对应的元素小于k的话,会将left设置为mid+1,而mid对应的元素是小于k的。
// 二分查找 注意是float k
int bisearch(vector<int>& data ,float k)
{
//左边界
int left=0;
//右边界
int right=data.size()-1;
//相等时仍需要 该方法返回k在data中的第一个下标 如果k不存在则返回第一个大于目标值的下标 故3.5是4 2.5是3 相减即为3的长度
while(left<=right)
{
//中间值
int mid=left+(right-left)/2;
//中点值小于k则移动左边界
if(data[mid]<k)
left=mid+1;
//中点値大于k则移动右边界
else if(data[mid]>k)
right=mid-1;
}
// 注意返回的是left啊! 比如3.5 right变成了3 但返回的是left为4 比如2.5 right变成了2 但返回的是left为3 最后下标相减即为3出现的次数
return left;
}
int GetNumberOfK(vector<int> data ,int k)
{
//分别查找k+0.5和k-0.5应该出现的位置中间部分全部是k
return bisearch(data,k+0.5)-bisearch(data,k-0.5);
}



京公网安备 11010502036488号