本文參考自《劍指offer》一書,代碼採用Java語言。html
更多:《劍指Offer》Java實現合集 java
數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如輸入一個長度爲9的數組{1, 2, 3, 2, 2, 2, 5, 4, 2}。因爲數字2在數組中出現了5次,超過數組長度的一半,所以輸出2。面試
思路一:數字次數超過一半,則說明:排序以後數組中間的數字必定就是所求的數字。數組
利用partition()函數得到某一隨機數字,其他數字按大小排在該數字的左右。若該數字下標恰好爲n/2,則該數字即爲所求數字;若小於n/2,則在右邊部分繼續查找;反之,左邊部分查找。函數
思路二:數字次數超過一半,則說明:該數字出現的次數比其餘數字之和還多post
遍歷數組過程當中保存兩個值:一個是數組中某一數字,另外一個是次數。遍歷到下一個數字時,若與保存數字相同,則次數加1,反之減1。若次數=0,則保存下一個數字,次數從新設置爲1。因爲要找的數字出現的次數比其餘數字之和還多,那麼要找的數字確定是最後一次把次數設置爲1的數字。測試
採用陣地攻守的思想:
第一個數字做爲第一個士兵,守陣地;count = 1;
遇到相同元素,count++;
遇到不相同元素,即爲敵人,玉石俱焚,count--;當遇到count爲0的狀況,又以新的i值做爲守陣地的士兵,繼續下去,到最後還留在陣地上的士兵,有多是主元素。
再加一次循環,記錄這個士兵的個數看是否大於數組通常便可。spa
測試算例 code
1.功能測試(存在或者不存在超過數組長度一半的數字)
2.特殊測試(null、1個數字)
//題目:數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例 //如輸入一個長度爲9的數組{1, 2, 3, 2, 2, 2, 5, 4, 2}。因爲數字2在數組中 //出現了5次,超過數組長度的一半,所以輸出2。 public class MoreThanHalfNumber { boolean isInputInvalid = true; //方法一:partition方法 public int MoreThanHalfNum_Solution(int [] array) { if(array==null ||array.length<=0) return 0; int low=0; int high=array.length-1; int index=partition(array,low,high); while(index!=array.length>>1){ if(index<array.length>>1){ low=index+1; index=partition(array,low,high); }else{ high=index-1; index=partition(array,low,high); } } //判斷次數是否超過一半 int num=array[index]; int times=0; for(int i=0;i<array.length;i++){ if(array[i]==num){ times++; } } if(times*2>array.length){ isInputInvalid=false; return num; } return 0; } private int partition(int[] array,int low ,int high){ int pivotKey=array[low]; while(low<high){ while(low<high && array[high]>=pivotKey) high--; int temp=array[low]; array[low]=array[high]; array[high]=temp; while(low<high && array[low]<=pivotKey) low++; temp=array[low]; array[low]=array[high]; array[high]=temp; } return low; } //方法二 public int MoreThanHalfNum_Solution2(int [] array) { if(array==null || array.length<=0) return 0; int num=array[0]; int count=1; for(int i=1;i<array.length;i++){ if(count==0) { num=array[i]; count++; } else if(array[i]==num) count++; else count--; } if(count>0){ int times=0; for(int i=0;i<array.length;i++){ if(array[i]==num){ times++; } } if(times*2>array.length){ isInputInvalid=false; return num; } } return 0; } }
1.length/2 用 length>>1 來代替,具備更高的效率;
2.本題中,找到了所求數字,別忘記判斷該數字的次數是否超過一半。
3.題目所要求的返回值爲int,因此若是數組不知足要求時,沒法經過返回值來告知是否出錯,因此這道題設置了一個全局變量來進行判斷。調用該方法時,須要記得對全局變量進行檢查。
4.方法一中,採用了partition()函數,該函數會改變修改的數組,所以在面試的時候,須要和麪試官討論是否能夠修改數組。
5.兩種方法的時間複雜度均爲O(n)。