题目描述
统计一个数字在排序数组中出现的次数。
一、二分查找思想
1.找到第一个k出现的位置,先二分查找入手,如果相等了,则向前一个寻找是否等于k,如果不相等则直接返回位置,即为第一个出现的位置,如果相等了,那么向左侧缩小范围,right的值变为前一个位置,继续递归查找。
2.找到最后一个k出现的位置,同上方法,只不过是若后一个等于k,则向右侧缩小,left等于后一个位置,继续递归查找。
3.二分查找的思想,能够准确无误地写出无bug的二分查找,关键点在于下标的选取while(left<=right),此时right取到数组n-1处left和right后面的变换都应该取middle-1和middle+1进行。
class Solution {
public:
int GetNumberOfK(vector<int> data ,int k) {
int len = data.size();
if(len == 0) return 0;
int number = 0;
int first = getFirstK(data, len, k, 0, len-1);
int last = getLastK(data, len, k, 0, len-1);
if(first > -1 && last > -1)
number = last - first + 1;
return number;
}
int getFirstK(vector<int> data, int len, int k, int left, int right) {
if(left > right) return -1;
int middle = left + ((right - left) >> 1);
if(data[middle] == k) {
if((middle > 0 && data[middle-1] != k) || middle == 0)
return middle;
else
right = middle - 1; //如果前一个数仍为k,那么就进一步缩小搜索范围,限定在前半部分[left,middled-1]
}
else if(data[middle] > k)
right = middle - 1;
else
left = middle + 1;
return getFirstK(data, len, k, left, right); //递归调用,直到找到第一个K为止
}
int getLastK(vector<int> data, int len, int k, int left, int right) {
if(left > right) return -1;
int middle = left + ((right - left) >> 1);
if(data[middle] == k) {
if((middle < len - 1 && data[middle+1] != k) || middle == len - 1)
return middle;
else
left = middle + 1; //这里是后半部分,限定在[middle+1, right]之间
}
else if(data[middle] > k)
right = middle - 1; //这里前后两部分通用的
else
left = middle + 1;
return getLastK(data, len, k, left, right);
}
};
二、使用STL
1.lower_bound返回第一个不小于目标数的迭代器(the value pointed by the iterator returned by this function may also be equivalent to val)
2.upper_bound返回第一个一个大于目标数的迭代器(the value pointed by the iterator returned by this function cannot be equivalent to val, only greater)
class Solution {
public:
int GetNumberOfK(vector<int> data ,int k) {
std::vector<int>::iterator low,up;
low = lower_bound(data.begin(), data.end(), k);
up = upper_bound(data.begin(),data.end(), k);
return up - low;
}
};