题目
统计一个数字在排序数组中出现的次数。
示例 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] <= 109nums是一个非递减数组-109 <= target <= 109
解析
由于题目给的nums 数组是递增且升序的, 因此可以找到 target第一次出现的位置first,和 target 最后一次出现位置last,则 target 出现的次数为 last - first + 1, 反之,如果没找到target, 出现次数为0
由于数组nums有序,查找target的可以使用二分查找,分别查找target的第一次出现索引first, 最后一次出现索引last
查找first的具体流程
- 令
k = target定义递归函数getFirstK(nums, k, start, end), 在start = 0, end = nums.length-1的范围中查找K - 如果
start > end, 返回-1, 说明没找到k - 声明
midIndex = Math.floor((start + end) / 2) - 如果
nums[midIndex] > k, 说明要缩小右边界end = midIndex -1 - 如果
nums[midIndex] < k, 说明要扩大左边界start = midIndex + 1 - 如果
nums[midIndex] == k, 此时要分为两种情况:- 如果
nums[midIndex-1] != k, 说明中间数字的前一个不等于k, 此时midIndex是k第一次出现的位置, 直接返回 - 如果
midIndex == 0, 说明中间数字为数组的第一个数字,不存在前一个数字,midIndex是k第一次出现的位置,直接返回 - 以上都不是的,说明中间数字的前一个数字也等于
k, 此时要缩小右边界,end = midIndex - 1
- 如果
- 递归执行
getFirstK(nums, k, start, end)
查找last的具体流程
- 令
k = target定义递归函数getLastK(nums, k, start, end), 在start = 0, end = nums.length-1的范围中查找K - 如果
start > end, 返回-1, 说明没找到k - 声明
midIndex = Math.floor((start + end) / 2) - 如果
nums[midIndex] > k, 说明要缩小右边界end = midIndex -1 - 如果
nums[midIndex] < k, 说明要扩大左边界start = midIndex + 1 - 如果
nums[midIndex] == k, 此时要分为两种情况:- 如果
nums[midIndex+1] != k, 说明中间数字的后一个不等于k, 此时midIndex是k最后一次出现的位置, 直接返回 - 如果
midIndex == nums.length - 1, 说明中间数字为数组的最后一个数字,不存在后一个数字,midIndex是k第一次出现的位置, 直接返回 - 以上都不是的,说明中间数字的前一个数字也等于
k, 此时要缩小右边界,start = midIndex + 1
- 如果
- 递归执行
getLastK(nums, k, start, end)
参考代码
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function(nums, target) {
// 第一次出现的位置
const k = target;
const first = getFirstK(nums, k, 0, nums.length - 1);
// 最后一次出现的位置
const last = getLastK(nums, k, 0, nums.length - 1);
// 如果first和last都能找到
if (first > -1 && last > -1) {
return last - first + 1;
}
// 没找到返回 0
return 0;
};
function getFirstK(nums, k, start, end) {
if (start > end) {
return -1;
}
let midIndex = Math.floor((start + end) / 2);
if (nums[midIndex] > k) {
end = midIndex - 1;
} else if (nums[midIndex] < k) {
start = midIndex + 1;
} else {
if (nums[midIndex - 1] != k || midIndex == 0) {
return midIndex;
} else {
end = midIndex - 1;
}
}
return getFirstK(nums, k, start, end);
}
function getLastK(nums, k, start, end) {
if (start > end) {
return -1;
}
let midIndex = Math.floor((start + end) / 2);
if (nums[midIndex] > k) {
end = midIndex - 1;
} else if (nums[midIndex] < k) {
start = midIndex + 1;
} else {
if (nums[midIndex + 1] != k || midIndex == nums.length - 1) {
return midIndex;
} else {
start = midIndex + 1;
}
}
return getLastK(nums, k, start, end);
}