题目
统计一个数字在排序数组中出现的次数。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: 0
限制:
- 0 <= 数组长度 <= 50000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof
解题思路
排序数组:直接想到二分法和双指针
本题使用二分法来解决
思路一:
- 查找目标值的右边界right
- 查找目标值的左边界left
- 计算出现次数right - left - 1
思路二:
- 查找目标值的右边界r1
- 查找目标值 - 1的右边界r2
- 计算出现次数r1 - r2
代码
思路一:
class Solution {
public int search(int[] nums, int target) {
// 本题使用二分法解决
int l = 0;
int r = nums.length - 1;
// 判断下标是否越界,最小的元素是否大于目标值,最大元素是否小于目标值
if (r < 0 || nums[l] > target || nums[r] < target) {
return 0;
}
// 查找目标值的右边界
while (l <= r) {
int m = l + ((r - l) >> 1);
if (nums[m] <= target) {
// 当nums[m] == target时,因为此时是为了查找目标值的右边界,所以也是进行左边界右移
l = m + 1;
} else {
r = m - 1;
}
}
int right = l;
// 提前判断目标值是否存在
if (r >= 0 && nums[r] != target) {
return 0;
}
// 计算目标值的左边界
// 记得重置左指针
l = 0;
while (l <= r) {
int m = l + ((r - l) >> 1);
if (nums[m] < target) {
l = m + 1;
} else {
// 当nums[m] == target时,因为此时是为了查找目标值的左边界,所以也是进行右边界左移
r = m - 1;
}
}
int left = r;
// 计算长度
return right - left - 1;
}
}
思路二:
class Solution {
public int search(int[] nums, int target) {
// 本题使用二分法解决
int l = 0;
int r = nums.length - 1;
// 判断下标是否越界,最小的元素是否大于目标值,最大元素是否小于目标值
if (r < 0 || nums[l] > target || nums[r] < target) {
return 0;
}
// 查找目标值的右边界和目标值 - 1的右边界
return binarySearch(nums, l, r, target) - binarySearch(nums, l, r, target - 1);
}
private int binarySearch(int[] nums, int l, int r, int target) {
// 查找目标值的右边界
while (l <= r) {
int m = l + ((r - l) >> 1);
if (nums[m] <= target) {
l = m + 1;
} else {
r = m - 1;
}
}
return l;
}
}
复杂度
- 时间复杂度:O(logn),执行两次二分查找,二分查找时间复杂度为logn
- 空间复杂度:O(1),占用常数级额外空间