数字在排序数组中出现的次数

本文介绍了一种高效算法,用于统计指定数字在一个已排序数组中出现的总次数。通过二分查找确定目标数字首次与末次出现的位置,进而计算其出现频率。适用于大数据集的快速查询。

数字在排序数组中出现的次数

统计一个数字在排序数组中出现的次数。

例如输入排序数组[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);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值