题目描述
统计一个数字k在排序数组中出现的次数。
思路1
直接遍历数组一遍,统计出现的次数,时间复杂度为O(logn)。代码如下:
class Solution {
public:
int GetNumberOfK(vector<int> data ,int k) {
if(data.empty())
return 0;
int ans = 0;
for(int i=0; i<data.size(); i++){
if(data[i]==k)
ans++;
}
return ans;
}
};
思路2
思路1没有用到“数组是排序的”这个条件。因为数组是排序的,我们可以使用二分查找来找到第一个k的下标firstk和最后一个k的下标lastk,k出现的次数就是lastk-firstk+1. 以找第一个k的下标为例,首先使用二分查找在范围[left, right]找到中间数字,如果中间数字data[mid]等于k,并且data[mid]-1不等于k,则说明mid就是第一个k的下标,否则则说明当前k的左边还有k,则缩小查找范围至[left, mid-1];如果中间数字大于k,则说明k在中间数字的左边,则缩小范围至[left, mid-1],如果中间数字小于k,则说明k在右边,则缩小范围至[mid+1, left],如果找不到则返回-1。可以用类似的方法查找最后一个k的下标,代码如下:
class Solution {
public:
int getFirstk(vector<int> data, int left, int right, int k){
if(left>right)
return -1;
int mid = (left+right)/2;
if(data[mid]==k){
if(mid==0||(mid>0 && data[mid-1]!=k))
return mid;
else right=mid-1;
}else if(data[mid]>k){
right=mid-1;
}else if(data[mid]<k){
left=mid+1;
}
return getFirstk(data, left, right, k);
}
int getLastk(vector<int> data, int left, int right, int k){
if(left>right)
return -1;
int mid = (left+right)/2;
if(data[mid]==k){
if(mid==data.size()-1 || (mid<data.size()-1 && data[mid+1]!=k))
return mid;
else left=mid+1;
}else if(data[mid]>k){
right=mid-1;
}else if(data[mid]<k){
left=mid+1;
}
return getLastk(data, left, right, k);
}
int GetNumberOfK(vector<int> data ,int k) {
if(data.empty())
return 0;
int firstk = getFirstk(data, 0, data.size()-1, k);
int lastk = getLastk(data, 0, data.size()-1, k);
if(firstk>-1&&lastk>-1)
return lastk-firstk+1;
else return 0;
}
};
由于二分查找的时间复杂度为O(logn),所以该算法的时间复杂度为O(logn)。