✍个人博客:https://blog.csdn.net/Newin2020?spm=1011.2415.3001.5343
📚专栏地址:剑指offer系列题解
📝原题地址:题目地址
📣专栏定位:为找工作的小伙伴整理常考算法题解,祝大家都能成功上岸!
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪
题目描述
统计一个数字在排序数组中出现的次数。
例如输入排序数组 [1,2,3,3,3,3,4,5] 和数字 3,由于 3 在这个数组中出现了 4 次,因此输出 4。
数据范围
数组长度 [0,1000]。
样例
输入:[1, 2, 3, 3, 3, 3, 4, 5] , 3 输出:4
方法一:二分法 O(logn)
我们可以通过二分的方法,去获取需要统计的数字在数组中的左右边界。
这里就需要用到二分法的两个模板,大家只用去记牢固定的二分法,以后就按照自己背的模板去实现即可,不需要每次都去重新写,这样需要重新思考边界情况而且会浪费很多时间。
下面代码中就包含了求左边界的模板以及求右边界的模板,不同题型可以改变 if
中的条件,但是要注意两个模板之间的区别。第一个的 mid = l + r
,而第二个的 mid = l + r + 1
,之所以不同是因为两者需要讨论的边界情况不同。
class Solution {
public:
int getNumberOfK(vector<int>& nums, int k) {
if (nums.empty()) return 0;
//获取左边界
int l = 0, r = nums.size() - 1;
while (l < r)
{
int mid = l + r >> 1;
if (nums[mid] >= k) r = mid;
else l = mid + 1;
}
if (nums[l] != k) return 0;
int left = l;
//获取右边界
l = 0, r = nums.size() - 1;
while (l < r)
{
int mid = l + r + 1 >> 1;
if (nums[mid] <= k) l = mid;
else r = mid - 1;
}
return r - left + 1;
}
};
方法二:利用自带函数二分 O(logn)
除了套用模板外,我们还可以利用 C++
自带的函数 lower_bound
和 upper_bound
,它们的用法如下:
-
lower_bound(起始地址,结束地址,要查找的数值)
从数组的begin
位置到end-1
位置二分查找第一个大于或等于 num 的数字,找到返回该数字的地址,不存在则返回end
。通过返回的地址减去起始地址begin
,得到找到数字在数组中的下标。 -
upper_bound(起始地址,结束地址,要查找的数值)
从数组的begin
位置到end-1
位置二分查找第一个大于 num 的数字,找到返回该数字的地址,不存在则返回end
。通过返回的地址减去起始地址begin
,得到找到数字在数组中的下标。
另外,需要注意的是这里获得的 right
和方法一有所不同,方法一是获取等于 3
的最后一个元素,而这里获取的是大于 3
的第一个元素。
class Solution {
public:
int getNumberOfK(vector<int>& nums, int k) {
auto left = lower_bound(nums.begin(), nums.end(), k);
auto right = upper_bound(nums.begin(), nums.end(), k);
return right - left;
}
};
欢迎大家在评论区交流~