「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战」
描述
统计一个数字在排序数组中出现的次数。
- 示例 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
复制代码
- 进阶:
- 如果给定的数组中含有负数会发生什么?问题会产生何种变化?如果允许负数出现,需要向题目中添加哪些限制条件?
解析
由题目可知,在排序数组中,寻找target,是否在数组存在,已经存在的次数;如果没有存在就返回0,否则就返回存在的次数。
直观的思路肯定是从前往后遍历一遍。用两个变量记录第一次和最后一次遇见 \textit{target}target 的下标,但这个方法的时间复杂度为 O(n)O(n),没有利用到数组升序排列的条件。
由于数组已经排序,因此整个数组是单调递增的,我们可以利用二分法来加速查找的过程。
如果存在target在数组中存在,那么他在数组中可以用下标给标示出来,那么我们可以找出数组中target出现的左边界left和有边界right,即返回的次数就是right-left-1。
示例
class Solution {
public int search(int[] nums, int target) {
//获取数组长度
int length=nums.length;
//因为这个数组里面的数字是排序好的,
//所以通过二分法来确定target对应在数组中出现的区域,区域内都是target值
int i=0;
int j=length-1;
//先确定目标区域的右边界
while(i<=j){
int m=(i+j)/2;
//if存在说明target所在范围在二分法的右边
if(nums[m]<=target){
i=m+1;
}else{
j=m-1;
}
}
int right=i;
if(j>0&&nums[j]!=target){
return 0;
}
i=0;j=length-1;
//确定目标的左边界
while(i<=j){
int m=(i+j)/2;
//target的左边界必然小于target的值
if(nums[m]<target){
i=m+1;
}else{
j=m-1;
}
}
int left=j;
//右区间-左区间-1 就是含的个数
return right-left-1;
}
}
复制代码
运行结果:
执行结果:通过
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:41.1 MB, 在所有 Java 提交中击败了81.55%的用户