剑指Offer(Java版):数字在排序数组中出现的次数

题目:统计一个数字在排序数组中出现的次数。例如输入排序数组为面试

{1,2,3,3,,3,3,4,5}和数字3,因为3在这个数组中出现了4次,所以输出4算法

既然输入的数组是排序的,那么咱们很天然的想到利用二分查找算法。在 题目给出的例子中,咱们能够先用二分查找算法找到第一个3.因为3可能出现屡次,所以咱们找到的3的左右两遍可能都是3,因而咱们在找到3的左右两边顺序 扫描,分别找出第一个3和最后一个3.由于要查找的数字在长度为n的数组中可能很出现O(n)次,因此顺序扫描的时间复杂度为O(n)。所以这种算法的效 率和直接从头至尾顺序扫描整个数组统计3出现的次数的方法是同样的。显然,面试官是不会满意这种算法,它会提示咱们还有更快的算法。数组

接下来咱们思考如何更好的利用二分查找算法。假设咱们统计数字k在排序数组中出现的次数。在前面的算法的时间主要消耗在如何肯定重复出现的第一个k和最后一个k的位置上,有没有能够利用的二分查找算法直接找到第一个k和最后一个k。排序

咱们先分析如何利用二分查找在数组中找到第一个k,二分查找算法老是 先拿数组的中间的数字和k作比较。若是中间的数字比k大,那么k只能出如今数组的前半段,下一轮咱们旨在数组的前半段查找就能够了。若是中间的数字比k 小,那么k只能出如今数组的后半段,下一轮咱们只在数组的后半段查找就能够了。若是中间的数字和k相等呢?咱们先判断这个数字是否是第一个k。若是位于中 间数字的前面一个数字不是k,此时中间的数字恰好就是第一个k。若是中间的数字的前面一个数字也是k,也就是说第一个k确定在数组的前半段,下一轮咱们仍 然须要在数组的前半段查找。递归

同理咱们利用上面的思路找到最后一个k。get

找到第一个k和最后一个k后就能够知道k出现的次数了,ast

实现代码以下:class

 

package cglib;test

public class jiekou {方法

    //递归找到排序数组中第一个k
     private int getFirstK(int[] arr,int k,int left,int right){  
            if(left > right)  
                return -1;  
            int middleIndex = (left+right)/2;  
            int middleData = arr[middleIndex];  
            if(middleData == k){ //若是中位数等于k
                if((middleIndex >0 && arr[middleIndex -1]!=k)|| middleIndex == 0)  
                    return middleIndex; //中位数是第一个k  
                else  
                    right = middleIndex -1;  //中位数不是第一个k,则往中位数左边找第一个k
            }  
            else if(middleData > k)//中位数大于k ,则第一个k确定在中位数左边
                right = middleIndex -1;  //往中位数左边找第一个k
            else  
                left = middleIndex +1; //中位数小于k ,则第一个k确定在中位数右边
            return getFirstK(arr,k,left,right); //递归
        }  
        //相同的思路,递归找到最后的一个k
        private int getLastK(int[] arr,int k,int left,int right){  
            if(left > right)  
                return -1;  
            int middleIndex = (left + right)/2;  
            int middleData = arr[middleIndex];  
            if(middleData == k){  
                if((middleIndex <arr.length -1 && arr[middleIndex+1]!=k) || middleIndex ==arr.length-1)  
                    return middleIndex;  
                else  
                    left = middleIndex+1;  //中位数不是最后一个k,则往中位数右边找最后个k
            }  
            else if(middleData <k){//中位数小于k,则往中位数右边找最后一个k  
                left = middleIndex +1;  
            }else  
                right = middleIndex -1;  //中位数大于k,则往中位数左边找最后一个k
            return getLastK(arr,k,left,right); //递归  
        }  
      //计算出k在数组中出现的次数
        public int getNumberOfK(int[] arr,int k){  
            int number = 0;  
            if(arr.length >0){  
                int first = getFirstK(arr,k,0,arr.length-1);  
                int last = getLastK(arr,k,0,arr.length -1);  
                if(first >-1 && last >-1)  
                    number =last-first+1;  
            }  
            return number;  
        }  
        public static void main(String[] args){  
            int[] arr= {1,2,3,3,3,3,4,5};  
            jiekou test = new jiekou();  
            System.out.println(test.getNumberOfK(arr, 3));  
        }
    }
   

输出:4

相关文章
相关标签/搜索