题目描述
统计一个数字在排序数组中出现的次数。
分析:遍历一遍数组可以得到结果,时间复杂度O(n),但是这完全没利用排序数组的特性。提到排序数组查找问题就想到二分查找,二分查找O( logn )找到k,但这个k的位置是不确定的,不知道是第几个k,如果能用两次二分查找找到第一个k和最后一个k,就能得到k的个数,并且时间复杂度是O(logN);
非递归:
class Solution {
public:
int GetNumberOfK(vector<int> data ,int k) {
int num = 0;
if(!data.empty()){
int first = GetFirstK(data, k);
int last = GetLastK(data, k);
if(first != -1 && last != -1)
num = last - first + 1;
}
return num;
}
int GetFirstK(const vector<int> &data, int k)
{
int low = 0;
int high = data.size() -1;
int mid = 0;
//二分查找必须是<=
while(low <= high){
mid = (low + high) / 2;
if(data[mid] == k){
if((mid > 0 && data[mid-1] != k) || mid == 0)
return mid;
else
high = mid-1;
}
else if(data[mid] > k)
high = mid - 1;
else
low = mid + 1;
}
return -1;
}
int GetLastK(const vector<int> &data, int k)
{
int low = 0;
int high = data.size() -1;
int mid = 0;
//二分查找必须是<=
while(low <= high){
mid = (low + high) / 2;
if(data[mid] == k){
if((mid < data.size()-1 && data[mid+1] != k) || mid == data.size()-1)
return mid;
else
low = mid + 1;
}
else if(data[mid] > k)
high = mid - 1;
else
low = mid + 1;
}
return -1;
}
};
递归:
classSolution {
public:
intGetNumberOfK(vector<int> data ,intk) {
if(data.empty()) return0;
intlast = GetLastK(data, k, 0, data.size()-1);
intfirst = GetFirstK(data, k, 0, data.size()-1);
if(last == -1|| first == -1)
return0;
else
returnlast - first + 1;
}
intGetFirstK(constvector<int>& data, intk, intlow, inthigh)
{
if(low > high) return-1;
intmid = (low+high)/2;
if(data[mid] == k)
{
if((mid > 0&& data[mid - 1] != k)
|| mid == 0)
returnmid;
else
high = mid - 1;
}
elseif(data[mid] > k)
high = mid - 1;
else
low = mid + 1;
returnGetFirstK(data, k, low, high);
}
int GetLastK(constvector<int>& data, intk, intlow, inthigh)
{
if(low > high) return-1;
intmid = (low + high)/2;
if(data[mid] == k)
{
if((mid < data.size() - 1&& data[mid+1] != k)
|| mid == data.size() - 1)
returnmid;
else
low = mid + 1;
}
elseif(data[mid] > k)
high = mid - 1;
else
low = mid + 1;
returnGetLastK(data, k, low, high);
}
};
这其实是二分查找的变形,类似的有查找第一个大于k的元素,第一个小于等于k的元素等等,总结起来就是:
// 这里必须是 <=
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] ? key) {
//... right = mid - 1;
}
else {
// ... left = mid + 1;
}
}
return xxx;