1. 程式人生 > >微信紅包-找出陣列中過半數的數字

微信紅包-找出陣列中過半數的數字

題目

春節期間小明使用微信收到很多個紅包,非常開心。在檢視領取紅包記錄時發現,某個紅包金額出現的次數超過了紅包總數的一半。請幫小明找到該紅包金額。寫出具體演算法思路和程式碼實現,要求演算法儘可能高效。

給定一個紅包的金額陣列gifts及它的大小n,請返回所求紅包的金額。
沒找到,返回0。

思路思路一:部分快速排序

受快速排序的partition函式的啟發,我們可以利用反覆呼叫partition函式來求的該數字。我們現在陣列中隨機選取一個數字,而後通過Partition函式返回該數字在陣列中的索引index,如果index剛好等於n/2,則這個數字便是陣列的中位數,也即是要求的數,如果index大於n/2,則中位數肯定在index的左邊,在左邊繼續尋找即可,反之在右邊尋找。這樣可以只在index的一邊尋找,而不用兩邊都排序,減少了一半排序時間。這種情況的平均時間複雜度大致為:T(n) = n+n/2+n/4+n/8+....+1,很明顯當n很大時,T(n)趨近於2n,也就是說平均情況下時間複雜度為O(n),但是這種情況下,最壞的時間複雜度依然為O(nn),最壞情況下,index總是位於陣列的最左或最右邊,這樣時間複雜度為T(n) = n+n-1+n-2+n-3+....+1 = n(n-1)/2,顯然,時間複雜度為O(nn),空間複雜度為O(1)。

部分快速排序的擴充套件

對於一個亂序的陣列,返回排序後,index為n的數字

對於以上的問題,也可以用部分快速排序思路去做

思路二

陣列中有一個數字出現的次數超過陣列長度的一半,也就是說它出現的次數比其他所有數字出現次數的和還要多。因此我們可以考慮在遍歷陣列的時候儲存兩個值: 一個是陣列中的一個數字, 一個是次數。當我們遍歷到下~個數字的時候,如果下一個數字和我們之前儲存的數字相同,則次數加l :如果下一個數字和我們之前儲存的數字,不同,則次數減1 。如果次數為黴,我們需要儲存下一個數字,並把次數設為1 。由於我們要找的數字出現的次數比其他所有數字出現的次數之和還要多,那麼要找的數字肯定是最後一次把次數設為1 時對應的數字。

程式碼
publicclassFindOverNumber{/**
     * 題目:陣列中有一個數字出現的次數超過陣列長度的一半,請找出這個數字
     *
     * @param numbers 輸入陣列
     * @return 返回的結果
     */publicstaticint moreThanHalfNum(int[] numbers){if(numbers ==null|| numbers.length <1){thrownewIllegalArgumentException("array length must large than 0");}// 用於記錄出現次數大於陣列一半的數
int result = numbers[0];// 於當前記錄的數不同的數的個數int count =1;// 從第二個數開始向後找for(int i =1; i < numbers.length; i++){// 如果記數為0if(count ==0){// 重新記錄一個數,假設它是出現次數大於陣列一半的 result = numbers[i];// 記錄統計值 count =1;}// 如果記錄的值與統計值相等,記數值增加elseif(result == numbers[i]){ count++;}// 如果不相同就減少,相互抵消else{ count--;}}// 最後的result可能是出現次數大於陣列一半長度的值// 統計result的出現次數 count =0;for(int number : numbers){if(result == number){ count++;}}// 如果出現次數大於陣列的一半就返回對應的值if(count > numbers.length /2){return result;}// 否則輸入異常else{thrownewIllegalArgumentException("invalid input");}}