题目描述
统计一个数字在排序数组中出现的次数。
例如输入排序数组 [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; } };
欢迎大家在评论区交流~