每日一题--数字在排序数组中出现的次数

一下子想到的解法是遍历,时间复杂度为O(n)
改进:排序的数组,想到二分查找查找数字的方法,这里迁移为找第一次出现该数字和最后一次出现该数字,最后得到数组中该数字出现的总次数。
如何在数组中找到第一个数字出现的位置????
二分查找总是先拿中间的值与k作比较,如果中间数字大于k,则第一个出现的肯定在数组的前半段,如果中间数字小于k,则第一个出现的肯定在数组的前半段,较为复杂的是:中间数字等于k,如果中间数字的前一个数字也为k,则第一次出现的在前半段,否则中间数字的位置即为第一次出现的位置。采用递归

考察:知识迁移能力

代码:

package core;

/**问题描述:统计一个数字在排序数组中出现的次数
 * 输入:{1,2,3,3,3,3,3,4,5}和3
 * 输出:5
 * Created by lxq on 2017/9/12.
 */
public class Problem2 {
    public static void main(String[] args){
        Problem2 problem2 = new Problem2();
        int[]array = {1,2,3,3,3,3,4,5};
        int k =  problem2.getNumberOfK(array,3);
        System.out.println(k);
    }
    public int getNumberOfK(int[] array,int k){
        int number = 0;
        if(array!=null){
            int first = getFirstK(array,k,0,array.length-1);
            int last = getLastK(array,k,0,array.length-1);
            if(first>-1&&last>-1){
                number = last-first+1;
            }
        }
        return number;
    }

    //利用二分查找,时间复杂度为O(logn),找到到最后一个k在数组中的下标
    private int getLastK(int[] array, int k, int start, int end) {
        if(start>end)
            return -1;
        int middleIndex = (end+start)/2;
        int middleData = array[middleIndex];
        if(middleData==k){
            //中间数字是最后一个k,
            //特殊情况:中间数字在数组中的最后位置,肯定就是最后一个
            if((middleIndex<array.length-1&&array[middleIndex+1]!=k)||middleIndex==array.length-1)
                return middleIndex;
            //后面位置也是k,说明最后一个k在后半段
            else
                start = middleIndex+1;
        }
        else if(middleData>k){
            //最后一个k在前半段
            end = middleIndex-1;
        }else {
            //最后一个k在后半段
            start = middleIndex+1;
        }
          return getLastK(array,k,start,end);
    }

    //利用二分查找,时间复杂度为O(logn),找到第一个k在数组中的下标
    private int getFirstK(int[] array, int k, int start, int end) {
        if(start>end)
            return -1;  //不包含k返回-1
        int middleIndex = (end+start)/2;
        int middleData = array[middleIndex];
        //如果中间数字==k,
        if(middleData==k){
            //中间数的前面一个数字是否也是k
            if((middleIndex>0&&array[middleIndex-1]!=k)||middleIndex==0)
                return middleIndex;
            //第一个数字在前半段,递归调用前半段
            else
                end = middleIndex-1;
        }
       //中间数字大于k,在前半段递归调用
        else if(middleData>k){
            end = middleIndex-1;
        }
        //中间数字小于k,在后半段递归调用
        else {
            start = middleIndex+1;
        }
        return getFirstK(array,k,start,end);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值