题目
统计一个数字在排序数组中出现的次数。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: 0
限制:
0 <= 数组长度 <= 50000
解题思路
定义递归函数getFirst(),用来查找第一个 target对应的坐标 first:
首先分析如何用二分查找算法在数组中找到第一个 target的坐标left。二分查找算法总是先拿数组中间的数字nums[mid]和target作比较。
- 1)如果nums[mid]>target,target只有可能出现在数组的前半段nums[start,mid-1],下一轮只在数组的前半段查找就可以了。
- 2)如果nums[mid]<target,target只有可能出现在数组的后半段nums[mid+1,end],下一轮只在数组的后半段查找就可以了。
- 3)如果nums[mid]=target,则需要判断nums[mid]是不是第一个target:
- 3.1)如果此时mid=0,即nums[mid]=nums[0]为数组中的第一个数字,或其前面的数字nums[mid-1]!=target,则 first = mid;
- 3.2)反之,若 mid>0 且 nums[mid-1]=target,那么第一个 target 肯定在数组的前半段 [start, mid-1],下一轮我们仍然需要在数组的前半段查找。
定义函数getLast(),用来查找最后一个 target对应的坐标 last,思路差不多同上。
在两个递归函数中,如果数组中没有目标值,则返回 -1;否则返回其下标。最后根据下标,就能计算出现的次数了。
复杂度分析:
时间复杂度:O(log N)。
空间复杂度:O(1)。
代码
class Solution {
public int search(int[] nums, int target) {
int res = 0;
if(nums.length>0){
int first = getFirst(nums, target, 0, nums.length-1);
int last = getLast(nums, target, 0, nums.length-1);
if(first != -1 && last != -1){
res = last-first+1;
}
}
return res;
}
private int getFirst(int[] nums, int target, int start, int end){
if(start>end){
return -1;
}
int mid = start + (end-start)/2;
if(nums[mid]==target){
if((mid > 0 && nums[mid-1] != target) || mid==0){
return mid;
}else{
end = mid-1;
}
}else if(nums[mid]<target){
start = mid+1;
}else{
end = mid-1;
}
return getFirst(nums, target, start, end);
}
private int getLast(int[] nums, int target, int start, int end){
if(start>end){
return -1;
}
int mid = start + (end-start)/2;
if(nums[mid]==target){
if((mid<nums.length-1 && nums[mid+1] != target) || mid==nums.length-1){
return mid;
}else{
start = mid+1;
}
}else if(nums[mid]<target){
start = mid+1;
}else{
end = mid-1;
}
return getLast(nums, target, start, end);
}
}