算法--微软面试:指定数字在数组中出现的次数
生活随笔
收集整理的這篇文章主要介紹了
算法--微软面试:指定数字在数组中出现的次数
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Q題目
在排序數組中,找出給定數字的出現次數,比如 [1, 2, 2, 2, 3] 中2的出現次數是3次。Answer解法
這道題要求出結果不難,但要求最有解的話,就需要花費一番功夫了。常見解法有如下四種:
定義: 要查詢的數字為key 查詢的數組為arr
1)暴力窮舉
直接從頭遍歷計數就可以了2)遍歷開始和最后一次出現的index
從前開始遍歷,遇到與key相同,則停止遍歷,得到startIndex
從后開始遍歷,遇到與key相同,則停止遍歷,得到endIndex
數字出現次數為:endIndex-startIndex
該做法比方法一好一些,減少了一部分計算次數
方法一和方法二代碼如下:
package 微軟面試題數字次數;import java.util.Arrays; import java.util.HashSet;public class Test1 {public static void main(String[] args) {int[] arr={1,3,7,7,7,7,8,9,9,10};System.out.println("方法一測試:不存在key--"+getNumTimes(arr, 11));System.out.println("方法一測試:存在一個key--"+getNumTimes(arr, 3));System.out.println("方法一測試:存多個key--"+getNumTimes(arr, 9));System.out.println();System.out.println("方法二測試:不存在key--"+getNumTimes2(arr, 11));System.out.println("方法二測試:存在一個key--"+getNumTimes2(arr, 3));System.out.println("方法二測試:存多個key--"+getNumTimes2(arr, 9));}//方法一:暴力解法--完整遍歷public static int getNumTimes(int[] arr,int key){int count=0;//超出arr的最大值和最小值就沒必要遍歷了if(key>=arr[0]&&key<=arr[arr.length-1]){for (int i : arr) {if(i==key){count++;}}}return count;}//方法二:遍歷出開頭和結尾public static int getNumTimes2(int[] arr,int key){int count=0;//key出現的次數int start=-1;//key第一次出現的位置--索引有index=0,所以這里用-1int end=-1;//key最后一次出現的位置//超出arr的最大值和最小值就沒必要遍歷了if(key>=arr[0]&&key<=arr[arr.length-1]){//計算startfor (int i = 0; i < arr.length; i++) {if(arr[i]==key){start=i;break;}}}//計算end--若start為最后一個元素或key(即start=-1)不存在時,沒必要求end了if(start!=-1 && start<arr.length-1){for(int i=arr.length-1;i>=0;i--){if(arr[i]==key){end=i;break;}}count=Math.abs(end-start+1);}return count;}}運行結果:
3)二分法查找所有數字
直接使用二分法去查找所有出現的值,相對于前兩種計算次數少一些
代碼如下:
package 微軟面試題數字次數;public class Test2 {//方法三:二分法查找//參數:arr--查找的數組 key--要查找的數字 // startIndex和endIndex為在數組arr中的查找范圍--startIndex:起始下標 endIndex:截止下標static int count=0;public static void getNumTimes4ByBinary(int[] arr, int key, int startIndex,int endIndex){int middle=(startIndex+endIndex)/2;if(startIndex>endIndex){return;//輸入的參數不合法}if(arr[middle]==key){count++;//向前找getNumTimes4ByBinary(arr, key, startIndex, middle-1);//向后找getNumTimes4ByBinary(arr, key, middle+1, endIndex);}else if (arr[middle]<key) {getNumTimes4ByBinary(arr, key, middle+1, endIndex);}else {getNumTimes4ByBinary(arr, key, startIndex, middle-1);}}public static void main(String[] args) {int[] arr={1,3,7,7,7,7,8,9,9,10};getNumTimes4ByBinary(arr, 7, 0 , arr.length-1);System.out.println("方法三測試:存在多個key--"+count);}}注意:count為static變量,所以測試時,只能分別測試三種情況
4)二分法查找和for循環結合
使用二分法查找數字,查詢到第一個key后馬上結束
根據key的下標向前和向后遍歷,直到與key不相同為止,獲得count
與前三種方法相比,大大減少了計算的次數,不過這還不是最佳算法
代碼如下:
package 微軟面試題數字次數;import java.util.Arrays; import java.util.HashSet;public class Test1 {public static void main(String[] args) {int[] arr={1,3,7,7,7,7,8,9,9,10};System.out.println();System.out.println("方法三測試:不存在key--"+getNumTimes3(arr, 11));System.out.println("方法三測試:存在一個key--"+getNumTimes3(arr, 3));System.out.println("方法三測試:存多個key--"+getNumTimes3(arr, 9));}//方法三:二分法 --先二分法查找判斷是否存在key,并獲得索引public static int getNumTimes3(int[] arr,int key){int count=0;//超出arr的最大值和最小值就沒必要遍歷了if(key>=arr[0]&&key<=arr[arr.length-1]){//判斷有沒有keyint index=Arrays.binarySearch(arr, key);if(index>=0){//存在key值//向前找for(int i=index;i>=0;i--){if(arr[i]!=key){break;}count++;}//向后找for(int i=index+1;i<arr.length;i++){if(arr[i]!=key){break;}count++;}}}return count;}}運行結果如下:
5)二分法查找開始和結束index
使用二分法查詢開始和結束的index,關鍵是邊界問題的判斷。
開始邊界:與前一個數字比較,若不相同則是邊界
結束邊界:與后一個數字比較,若不相同則是邊界
與方法四相比,大多數情況下,該方法更計算次數更少,在少部分情況下,方法是更好。但總體上方法5更好。
代碼如下:
package 微軟面試題數字次數;public class Test3 {public static void main(String[] args) {int[] arr={1,3,7,7,7,7,8,9,9,10};System.out.println("方法五測試:不存在key--"+GetNumberOfK(arr, 11));System.out.println("方法五測試:存在一個key--"+GetNumberOfK(arr, 3));System.out.println("方法五測試:存多個key--"+GetNumberOfK(arr, 9));}// (1)GetFirstK:找到數組中第一個k的下標。如果數組中不存在k,返回-1public static int GetFirstK(int[] data, int k, int start, int end) {if (start > end) {return -1;}int middIndex = (start + end) / 2;int middData = data[middIndex];if (middData == k) {if ((middIndex > 0 && data[middIndex - 1] != k) || middIndex == 0) {return middIndex;} else {end = middIndex - 1;}} else if (middData > k) {end = middIndex - 1;} else {start = middIndex + 1;}return GetFirstK(data, k, start, end);}// (2)GetLastK:找到數組中最后一個k的下標。如果數組中不存在k,返回-1public static int GetLastK(int[] data, int k, int start, int end) {if (start > end) {return -1;}int middIndex = (start + end) / 2;int middData = data[middIndex];if (middData == k) {if ((middIndex < data.length - 1 && data[middIndex + 1] != k) || middIndex == end) {return middIndex;} else {start = middIndex + 1;}} else if (middData > k) {end = middIndex - 1;} else {start = middIndex + 1;}return GetLastK(data, k, start, end);}// (3)GetNumberOfK:找到數組中第一個和最后一個k的下標進行減法運算得到最終結果public static int GetNumberOfK(int[] data, int k) {int number = 0;if (data != null && data.length > 0) {int first = GetFirstK(data, k, 0, data.length - 1);int last = GetLastK(data, k, 0, data.length - 1);if (first > -1 && last > -1) {number = last - first + 1;}}return number;}}測試結果:
總結
以上是生活随笔為你收集整理的算法--微软面试:指定数字在数组中出现的次数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jQuery中 :first 和 :la
- 下一篇: oracle层次查询中prior与自上而