剑指Offer(Java版):数字在排序数组中出现的次数
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
題目:統(tǒng)計(jì)一個(gè)數(shù)字在排序數(shù)組中出現(xiàn)的次數(shù)。例如輸入排序數(shù)組為
{1,2,3,3,,3,3,4,5}和數(shù)字3,由于3在這個(gè)數(shù)組中出現(xiàn)了4次,因此輸出4
既然輸入的數(shù)組是排序的,那么我們很自然的想到利用二分查找算法。在 題目給出的例子中,我們可以先用二分查找算法找到第一個(gè)3.由于3可能出現(xiàn)多次,因此我們找到的3的左右兩遍可能都是3,于是我們?cè)谡业?的左右兩邊順序 掃描,分別找出第一個(gè)3和最后一個(gè)3.因?yàn)橐檎业臄?shù)字在長(zhǎng)度為n的數(shù)組中可能很出現(xiàn)O(n)次,所以順序掃描的時(shí)間復(fù)雜度為O(n)。因此這種算法的效 率和直接從頭到尾順序掃描整個(gè)數(shù)組統(tǒng)計(jì)3出現(xiàn)的次數(shù)的方法是一樣的。顯然,面試官是不會(huì)滿意這種算法,它會(huì)提示我們還有更快的算法。
接下來(lái)我們思考如何更好的利用二分查找算法。假設(shè)我們統(tǒng)計(jì)數(shù)字k在排序數(shù)組中出現(xiàn)的次數(shù)。在前面的算法的時(shí)間主要消耗在如何確定重復(fù)出現(xiàn)的第一個(gè)k和最后一個(gè)k的位置上,有沒(méi)有可以利用的二分查找算法直接找到第一個(gè)k和最后一個(gè)k。
我們先分析如何利用二分查找在數(shù)組中找到第一個(gè)k,二分查找算法總是 先拿數(shù)組的中間的數(shù)字和k做比較。如果中間的數(shù)字比k大,那么k只能出現(xiàn)在數(shù)組的前半段,下一輪我們旨在數(shù)組的前半段查找就可以了。如果中間的數(shù)字比k 小,那么k只能出現(xiàn)在數(shù)組的后半段,下一輪我們只在數(shù)組的后半段查找就可以了。如果中間的數(shù)字和k相等呢?我們先判斷這個(gè)數(shù)字是不是第一個(gè)k。如果位于中 間數(shù)字的前面一個(gè)數(shù)字不是k,此時(shí)中間的數(shù)字剛好就是第一個(gè)k。如果中間的數(shù)字的前面一個(gè)數(shù)字也是k,也就是說(shuō)第一個(gè)k肯定在數(shù)組的前半段,下一輪我們?nèi)?然需要在數(shù)組的前半段查找。
同理我們利用上面的思路找到最后一個(gè)k。
找到第一個(gè)k和最后一個(gè)k后就可以知道k出現(xiàn)的次數(shù)了,
實(shí)現(xiàn)代碼如下:
?
package cglib;
public class jiekou {
?? ?//遞歸找到排序數(shù)組中第一個(gè)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){ //如果中位數(shù)等于k
?? ???????????? if((middleIndex >0 && arr[middleIndex -1]!=k)|| middleIndex == 0) ?
?? ???????????????? return middleIndex; //中位數(shù)是第一個(gè)k ?
?? ???????????? else ?
?? ???????????????? right = middleIndex -1;? //中位數(shù)不是第一個(gè)k,則往中位數(shù)左邊找第一個(gè)k
?? ???????? } ?
?? ???????? else if(middleData > k)//中位數(shù)大于k ,則第一個(gè)k肯定在中位數(shù)左邊
?? ???????????? right = middleIndex -1;? //往中位數(shù)左邊找第一個(gè)k
?? ???????? else ?
?? ???????????? left = middleIndex +1; //中位數(shù)小于k ,則第一個(gè)k肯定在中位數(shù)右邊
?? ???????? return getFirstK(arr,k,left,right); //遞歸
?? ???? } ?
?? ???? //相同的思路,遞歸找到最后的一個(gè)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;? //中位數(shù)不是最后一個(gè)k,則往中位數(shù)右邊找最后個(gè)k
?? ???????? } ?
?? ???????? else if(middleData <k){//中位數(shù)小于k,則往中位數(shù)右邊找最后一個(gè)k ?
?? ???????????? left = middleIndex +1; ?
?? ???????? }else ?
?? ???????????? right = middleIndex -1;? //中位數(shù)大于k,則往中位數(shù)左邊找最后一個(gè)k
?? ???????? return getLastK(arr,k,left,right); //遞歸 ?
?? ???? } ?
?? ?? //計(jì)算出k在數(shù)組中出現(xiàn)的次數(shù)
?? ???? 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
轉(zhuǎn)載于:https://my.oschina.net/u/2822116/blog/726222
總結(jié)
以上是生活随笔為你收集整理的剑指Offer(Java版):数字在排序数组中出现的次数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: JAVA 基础 (一)
- 下一篇: Java学习日志(23-3-网络编程-T