数字在排序数组中出现的次数
统计一个数字在排序数组中出现的次数。
例如输入排序数组[1, 2, 3, 3, 3, 3, 4, 5]和数字3,由于3在这个数组中出现了4次,因此输出4。
思路:
由于是排好序的我们只需找到重复数字出现的第一次index和最后一次index相减加就能得到次数
用二分的方式找到start index 和end index
y轴代表数字的大小,x轴代表索引的大小
第一次我们要找左边的点,这个点有一个性质就是他左边的点都小于k,右边的都大于等于k
我们用二分, mid = l +r / 2 , 如果num[mid] 小于k , 说明目标点在区间的右半部分,l就要更新, 由于此时的num[mid]不等于k,不在所需范围内,所以要把 l 更新为 mid +1,而不是mid,如果 nums[mid]>=k, 说明他也能等于k,就把r更新为mid
最后就能找到start index
第二次找右边的点,如果num[mid] <=k,就将 mid 更新为 l 否则就把r 更新为mid +1;
最后就能找到end index
public int getNumberOfK(int[] nums, int k) {
int l = 0;
int r = nums.length-1;
while(l<r){
int mid = (l+r)/2;
if(nums[mid]<k){
l = mid+1;
}else{
r = mid ;
}
}
if(nums[l]!=k)
return 0;
int left = l;
l = 0;r = nums.length-1;
while(l<r){
int mid = (l+r+1)/2;
if(nums[mid]<=k){
l = mid;
}else{
r = mid -1;
}
}
return r-left+1;
}
还有一种用递归写的简单易理解的方法:一直找num【mid】==k 并且 num【mid-1】!=k
num 【mid】 = k 并且 num【mid +1】!= k的start和end
private int getNumberOfK(int [] array,int k){//{3, 3, 3, 3, 4, 5};
if(array==null||array.length<=0){
return 0;
}
int firstK=getFirstK(array,0,array.length-1,k);//firstK是k的第一个元素的索引值
if(firstK==-1){//
return 0;
}
int lastK=getLastK(array,firstK,array.length-1,k);//从第一个出现k的索引开始
return lastK-firstK+1;//找到k在数组中的相同元素的两个索引 得到个数,因为已经排完序了
}
private int getLastK(int[] array, int start, int end, int k) {//在后半段中返回末个k的索引号
if(start>end){
return -1;
}
int mid=(start+end)>>1;//平分
if(array[mid]==k){
if(mid==array.length-1|| array[mid+1]!=k){//已经到末尾了,或右侧第一个元素不是k 就不用查了,肯定是中间元素是k
return mid;
}else{
start=mid+1;//右侧
}
}else if(array[mid]<k){
start=mid+1;//新的start 右侧查找
}else{// array[mid]>k
end=mid-1;//新的end 左侧查找
}
return getLastK(array,start,end,k);
}
private int getFirstK(int[] array, int start, int end, int k) {//在前半段中 返回首个k的索引号
if(start>end){
return -1;
}
int mid=(start+end)>>1;
if(array[mid]==k){//在中间找到了,
if(mid==0 || array[mid-1]!=k){//mid处的k值是第一个k 正好是需要的结果
return mid;
}else{
end=mid-1;//中间的左侧还右k,继续找
}
}else if(array[mid]<k){
start=mid+1;//在右侧查找
}else{//array[mid]>k 左侧
end=mid-1;
}
return getFirstK(array,start,end,k);
}