剑指offer:数字在排序数组中出现的次数

题目:统计一个数字在排序数组中出现的次数。例如输入排序数组{1, 2, 3, 3,3, 3, 4, 5}和数字3,由于3在这个数组中出现了4次,因此输出4。

分析:对于例子来说,如果采用二分法找到某一个3后,再往前遍历和往后遍历到第一个和最后一个3,在长度为n的数组中有可能出现O(n)个3,因此这样的扫描方法时间复杂度为O(n),效率与从头到尾扫描一样,速度太慢。

  这题关键是找到第一个和最后一个3,因此我们尝试改进二分法:中间数字比3大或者小的情况与之前类似,关键是中间数字等于3的情况,这时可以分类讨论如下:

  1)如果中间数字的前一个数字也等于3,说明第一个3在前面,继续在前半段查找第一个3;

  2)如果中间数字的前一个数字不等于3,说明该位置是第一个3;

  3)如果中间数字的后一个数字也等于3,说明最后一个3在后面,继续在后半段查找最后一个3;

  2)如果中间数字的后一个数字不等于3,说明该位置是最后一个3;

 

测试算例 

  1.功能测试(数字出现次数为0、1、2等)

  2.边界值测试(数组只有一个数字,查找数字为第一个或者最后一个)

  2.特殊测试(null)

/题目:统计一个数字在排序数组中出现的次数。例如输入排序数组{1, 2, 3, 3,
//3, 3, 4, 5}和数字3,由于3在这个数组中出现了4次,因此输出4。
 
public class NumberOfK {
    public int GetNumberOfK(int [] array , int k) {
        if(array==null || array.length<=0)
            return 0;
         int firstK = getFirstK(array,0,array.length-1,k);
         if(firstK == -1)
             return 0;
         int lastK = getLastK(array,firstK,array.length-1,k);
         return lastK-firstK+1;
     }
       
     private int getFirstK(int[] arr, int start, int end,int k){
         if(start>end)
             return -1;
         int mid = (start+end)>>1;
         if(arr[mid]==k){
             if( mid == 0 ||arr[mid-1]!=k )
                 return mid;
             else
                 end = mid-1;
         }else if(arr[mid]<k){
             start = mid+1;
         }else{
             end = mid-1;
         }
         return getFirstK(arr,start,end,k);
     }
       
     private int getLastK(int[] arr, int start, int end,int k){
         if(start>end)
             return -1;
         int mid = (start+end)>>1;
         if(arr[mid]==k){
             if(mid==arr.length-1 || arr[mid+1]!=k )
                 return mid;
             else
                 start = mid+1;
         }else if(arr[mid]<k){
             start = mid+1;
         }else{
             end = mid-1;
         }
         return getLastK(arr,start,end,k);
     }
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值