1.题目
统计一个数字在排序数组中出现的次数。
2.我的题解
2.1 rank()
方法
rank()
方法用于在排序数组中将一个数插入到正确的位置,它可以返回一个数将被放到的“正确的位置”:
- 如果数组中有此数,将返回该数出现的位置(该数有多个位置的话不确定是哪个位置);
- 如果数组中没有此数,将返回该数组中大于该数的第一个位置,即该数将被插入的正确的位置。
- 采用二分法实现。
- 将参数改成
double
,用个小技巧可以方便地解决本问题,但是如果原数组是double
的那么问题就不好办了。假如数组是{1,1,2,2,3,3}
,可以查询0.5
和1.5
的位置,相减就可以得到1
的个数。如果查询1
和3
的位置,相减得到的却不是2
的个数,而是1,2
的总数。同理double
型数组不适用。
class Solution {
int MyRank(vector<int> &data,double i) {
int l = 0, r = data.size() - 1;
while (l <= r) {
int mid = (l + r) / 2;
if (data[mid] < i)l = mid + 1;
else if (data[mid] > i)r = mid-1;
else return mid;
}
return l;
}
public:
int GetNumberOfK(vector<int> data ,int k) {
if(data.size()==0)return 0;
return MyRank(data,k+0.5)-MyRank(data,k-0.5);
}
};
当然也可以分别获取一个数第一次出现和最后一次出现的位置:
- 相减加一即为结果;
- 注意实现时对
==
情况的不同处理。 - 要与
rank()
区分开来,查找索引的方法中找不到返回-1
,rank()
中找不到会返回第一个更大的数的位置。
class Solution {
int indexFirst(vector<int> &data, int i) {
int l = 0, r = data.size() - 1;
while (l <= r) {
int mid = (l + r) / 2;
if (data[mid] < i)l = mid + 1;
else if (data[mid] > i)r = mid - 1;
else {
if (mid == l || data[mid - 1] != i)return mid;
else r = mid - 1;
}
}
return -1;
}
int indexLast(vector<int> &data, int i) {
int l = 0, r = data.size() - 1;
while (l <= r) {
int mid = (l + r) / 2;
if (data[mid] < i)l = mid + 1;
else if (data[mid] > i)r = mid - 1;
else {
if (mid == r || data[mid + 1]!= i)return mid;
else l = mid + 1;
}
}
return -1;
}
public:
int GetNumberOfK(vector<int> data ,int k) {
int last=indexLast(data,k);
int first=indexFirst(data,k);
return last==-1?0:last-first+1;
}
};
3.别人的题解
3.1 调用upper_bound()和lower_bound()
class Solution {
public:
int GetNumberOfK(vector<int> data ,int k) {
return upper_bound(data.begin(),data.end(),k)
- lower_bound(data.begin(),data.end(),k);
}
};
3.2 调用count()
class Solution {
public:
int GetNumberOfK(vector<int> data ,int k) {
return count(data.begin(),data.end(),k);
}
};
4.总结与反思
(1)indexFirst(),indexLast()
中相等情况的处理;
(2)rank()
方法,除了用于排序数组中,在二叉树中也有重要应用。