题目描述
统计一个数字在排序数组中出现的次数。
示例1:
输入:nums = [5,7,7,8,8,10],target = 8
输出:2
示例2:
输入:nums = [5,7,7,8,8,10],target = 6
输出:0
提示:
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums 是一个非递减数组
-109 <= target <= 109
解题思路
此题主要考察二分查找变体问题,首先查找第一个值等于给定值的元素,拿到第一个值的下标后就可以往后遍历直到不等于给定值的元素就退出。我们可以定义一个计数器count来计算循环次数,此时count的值就是我们要的结果。
代码实现
1. 查找第一个值等于给定值的元素
public static int getPos(int[] nums, int target) {
int low = 0;
int high = nums.length - 1;
while (low <= high) {
// 等效于(low+high)/2,因为计算机对位运算更快
int mid = low + ((high - low) >> 1);
if (nums[mid] > target)
high = mid - 1;
else if (nums[mid] < target)
low = mid + 1;
else {
/*
* nums[mid]与要查找的value的大小关系有3种情况:大于、小于和等于。大于和小于这两种情况
* 很好理解。那么,当nums[mid]==value的时候,nums[mid]就是我们要找的元素。如何确定这
* 个nums[mid]值是不是第一个呢?
* 1.如果mid==0,也就是说,这个元素已经是数组的第一个元素,那么它肯定就是我们要找的第
* 一个值等于给定值的元素;
* 2.如果mid!=0,但nums[mid]的前一个元素nums[mid - 1]不等于target,那么说明
* nums[mid]就是我们要找的第一个值等于给定值的元素。
*/
if ((mid == 0) || (nums[mid - 1] != target))
return mid;
else
// 否则说明前面还有元素与target相等,我们就继续查找,因为要查找的元素肯定出现在
// [low, mid - 1]区间。
high = mid - 1;
}
}
return -1;
}
2. 遍历
public int search(int[] nums, int target) {
int pos = getPos(nums, target)
if (pos == -1)
return 0;
int count = 0;
while (pos < nums.length && nums[pos] == target) {
count++;
pos++;
}
return count;
}
总结
- 遇到像这种有序查找问题首先想到的是二分查找,一般都是考察二分查找的变体问题。
- 二分查找算法时间复杂度是O(logn)。
- 二分查找的底层必须依赖数组,并且要求数据是静态有序的。
- 适用于较大规模的数据的查找问题。