有序数组一定是二分,二分查找查找一个数字的时间复杂度是O(logn),比直接遍历数组好多了。这道题我们找出第一次出现k的下标和第二次出现k的下标,两者相减+1即可,
找第一次出现的下标,因为是递归,递归边界就是lo>hi(为啥自己推去)。如果mid位的值小于k,证明去后半部分找,mid位的值大于k,证明去前半部分找。如果等于,就判断mid的前一位是否为k,如果为k,就去前半部分找(mid位直接舍弃,因为它肯定不可能是第一位了),如果前一位不是,就返回mid。找最后一位也是类似。
class Solution {
public:
int findFirstK(vector<int>& data, int k, int lo, int hi){
if(lo > hi) return -1;
int mid = lo + (hi-lo)/2;
if(data[mid] < k){
return findFirstK(data, k, mid+1, hi);
}
else if(data[mid] > k){
return findFirstK(data, k, lo, mid-1);
}
else{
if(data[mid-1] == k) return findFirstK(data, k, lo, mid-1);
else return mid;
}
}
int findLastK(vector<int>& data, int k, int lo, int hi){
if(lo > hi) return -1;
int mid = lo + (hi -lo)/2;
if(data[mid] < k){
return findLastK(data, k, mid+1, hi);
}
else if(data[mid] > k){
return findLastK(data, k, lo, mid-1);
}
else{
if(data[mid+1] == k) return findLastK(data, k, mid+1, hi);
else return mid;
}
}
int GetNumberOfK(vector<int> data ,int k) {
//有序数组=二分=O(logn)
//绝对是错误的方法
/*int cnt = 0;
for(int i = 0; i < data.size(); ++i){
if(data[i] == k) cnt++;
}
return cnt;*/
//用两次二分找出第一个出现的k和最后一个出现的k的位置
//找第一个:都先和中间的比,如果中间比k大,去左半部分
//如果中间比k大,去右边。如果一样大,判断前一位是否还是k,如果是就去前面
//如果不是就是当前位
int cnt = 0;
if(data.size() > 0){
int firstK = findFirstK(data,k,0,data.size()-1);
int lastK = findLastK(data,k,0,data.size()-1);
if(lastK!=-1 && firstK != -1) cnt = lastK-firstK+1;
}
return cnt;
}
};