题目描述
统计一个数字在排序数组中出现的次数。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: 0
限制:
0 <= 数组长度 <= 50000
解法一
因为参数是整形,可以用二分查找K-0.5、K+0.5 两数应该插入的位置,相减即次数。
解法二
二分查找出任意target值,再左右遍历。
int search(int* nums, int numsSize, int target){
if(nums == NULL|| numsSize == 0) return NULL;
int i = 0;
int j = numsSize - 1;
int mid;
int cnt = 0;
while(i<=j)
{
mid = (i+j)/2;
if(nums[mid] < target) i = mid+1;
else if(nums[mid] > target) j = mid - 1;
//找到target
else{
for(int site = mid;site >= 0&&nums[site] == target;site--,cnt++); //左计数
for(int site = mid+1;site <= numsSize-1&&nums[site] == target;site++,cnt++); //右计数
return cnt;
}
}
//数组中不存在target
return 0;
}
注意计数时的site值判断,防止数组越界。
注意数组中不存在target时的返回。
解法三
二分查找左右边界,边界差值为出现次数。
int search(int* nums, int numsSize, int target){
if(nums == NULL|| numsSize == 0) return NULL;
/*int cnt = 0;
for(int i = 0;i < numsSize;i++)
{
if(nums[i] == target) cnt++;
if(nums[i] > target) break;
}
return cnt;*/
int i = 0;
int j = numsSize - 1;
int left;
int right;
int m;
//二分查找左边界
while(i <= j)
{
m = (i+j)/2;
if(nums[m] < target) i = m+1; //target在[m+1,j]区间
else if(nums[m] > target) j = m-1; //target在[i,m-1]区间
else if(nums[m] == target) j = m-1; //找到了target,左边界在[i,m-1]区间
}
left = j;
i = 0;
j = numsSize - 1;
//二分查找右边界
while(i <= j)
{
m = (i+j)/2;
if(nums[m] < target) i = m+1; //target在[m+1,j]区间
else if(nums[m] > target) j = m-1; //target在[i,m-1]区间
else if(nums[m] == target) i = m+1; //找到了target,左边界在[m+1,j]区间
}
right = i;
return right-left-1;
}
复杂度分析:
时间复杂度 O(log N): 二分法为对数级别复杂度。
空间复杂度 O(1)O(1) : 几个变量使用常数大小的额外空间。