题目描述
统计一个数字在排序数组中出现的次数。
思路1:直接用二分法找出要找的数字K,然后通过两个while()循环,分别朝前和后扫描,得到K的个数; 但是当K的个数较多时,前后扫描相当于顺序查找,时间复杂度仍然很高。
思路2:用二分法,采用递归的方式,分别找到第一个K的下标和,最后一个K的下标,然后根据两个下标的差得出K的个数,代码如下:
class Solution {
public:
int GetNumberOfK(vector<int> data ,int k) {
int count =0;
if(data.size() <=0)
return 0;
int first = getFirstK(data,k,0,data.size()-1);
int last = getLastK(data,k,0,data.size()-1);
if(first==-1 || last==-1)
return 0;
return last-first+1;
}
int getFirstK(vector<int> data,int k,int start,int end){
if (start > end)
return -1; //数组中不包含数字,返回-1
int mid = (start+end)>>1;
if(data[mid]==k){
if((mid>0 && data[mid-1] != k)||mid==0)
return mid;
else
end = mid - 1;
}
else if(data[mid]>k)
end = mid-1;
else
start = mid+1;
return getFirstK(data,k,start,end);
}
int getLastK(vector<int> data,int k,int start,int end){
if (start > end)
return -1; //数组中不包含数字,返回-1
int mid = (start+end)>>1;
if(data[mid]==k){
if((mid < data.size()-1 && data[mid+1] != k)||mid==data.size()-1)
return mid;
else
start = mid + 1;
}
else if(data[mid]>k)
end = mid-1;
else
start = mid+1;
return getLastK(data,k,start,end);
}
};
思路3:和思路二类似,不采用递归的方式,直接用二分法,注意易错点!!!
class Solution {
public:
int GetNumberOfK(vector<int> data ,int k) {
if(data.size() == 0)
return 0;
int left = firstk(data,k);
int right = lastk(data,k);
if(left == -1 || right == -1)
return 0;
return right-left+1;
}
int firstk(vector<int> data,int k){
int left = 0;
int right = data.size()-1;
int mid = (left+right)/2;
while(left <= right){
if(data[mid] == k){
if((mid-1>=left && data[mid-1]!= k) || mid==left)
return mid;
//!!!!犯错处,当mid位和mid-1位均等于k,取right=mid-1,不然可能出现死循环。
right = mid-1;
}
else if(data[mid] <k)
left = mid+1;
else
right = mid-1;
mid = (left+right)/2;
}
return -1;
}
int lastk(vector<int> data,int k){
int left = 0;
int right = data.size()-1;
int mid = (left+right)/2;
while(left <= right){
if(data[mid] == k){
if((mid+1<=right && data[mid+1]!=k) || mid==right)
return mid;
//!!!!犯错处,当mid位和mid+1位均等于k,取left=mid+1,不然可能出现死循环。
left = mid+1;
}
else if(data[mid] <k)
left = mid+1;
else
right = mid-1;
mid = (left+right)/2;
}
return -1;
}
};
思路四:(最优思路)
由于data中都是整数,所以可以稍微变一下,不是搜索k的两个位置,而是搜索k-0.5和k+0.5
//这两个数应该插入的位置,然后相减即可。
class Solution {
public:
int GetNumberOfK(vector<int> data ,int k) {
return biSearch(data, k+0.5) - biSearch(data, k-0.5) ;
}
private:
int biSearch(const vector<int> & data, double num){
int s = 0, e = data.size()-1;
while(s <= e){
int mid = (e - s)/2 + s;
if(data[mid] < num)
s = mid + 1;
else if(data[mid] > num)
e = mid - 1;
}
return s;
}
};