[資料結構與演算法]15 兩行程式碼就可以搞定求眾數,但還有更巧的

鄭璐璐發表於2020-04-18

這個週末刷了幾道演算法題,把其中一個比較不錯的分享給你~

給定一個大小為 n 的陣列,找到其中的多數元素。多數元素是指在陣列中出現次數大於 ⌊ n/2 ⌋ 的元素。
你可以假設陣列是非空的,並且給定的陣列總是存在多數元素。

示例 1:
輸入: [3,2,3]
輸出: 3

示例 2:
輸入: [2,2,1,1,1,2,2]
輸出: 2

哦,原來是求眾數,注意一下哈,這裡的眾數是指"在陣列中出現次數大於 ⌊ n/2 ⌋ 的元素",不要問我為什麼要你們注意一下這個條件,因為我鑽牛角尖了!

拿到這個題目,我的第一反應就是,那我給這個陣列排個序然後取中間的值不就得了?
所以程式碼就只有兩行:

Arrays.sort(nums);
return nums[nums.length >> 1];

寫完程式執行,一點兒毛病都沒有,簡簡單單兩行程式碼就搞定,那一刻我覺得我就是個天才!
後來夢醒了,冷靜分析了一下,我去這樣的程式碼簡單是簡單,但是時間複雜度是 O(nlogn) ,空間複雜度是 O(logn)
所以有沒有更好的解決方案呢?能讓它的時間複雜度和空間複雜度都降下來
必須得有哇!要不然我寫這篇文章是為了啥
這種比較好的解決方案就是摩爾投票法

這個方法理解起來有點兒繞,我先來講講,這一塊兒看懂了,我們們再往下走
先回到現實生活中,投票的時候我們們是怎麼投的呢?大家每個人都選一個人,然後開始拆開紙團瞅瞅選的是誰,剛開始預設大家都是 0 票,然後紙條上投的是誰,這個人就多一票,最後看誰的票數比較多.
回到我們們這個題目,既然是眾數,而且出現的次數大於 ⌊ n/2 ⌋ ,那我們可以假設一個數就是要求的眾數,同時設定這個數字出現的次數為 0 ,然後和接下來的數字進行比較,如果一樣呢,我們們把這個數字出現的次數加上 1 ,如果不一樣,就讓次數減 1 ,當這個值減到 0 時,說明剛開始假設的數字不是眾數,那就換當前的這個數字,繼續迴圈
這樣最後這個數字出現的次數一定是大於等於 0 的,要不然就不符合 出現的次數大於 ⌊ n/2 ⌋ 這個題意了
最後,將真正的眾數返回即可
具體程式碼可見下面:

int count = 0 ;
Integer candidate = null;

    for(int num : nums){
        if (count == 0){
            candidate = num;
        }
        count += ( num == candidate ) ? 1 : -1 ;
    }
return candidate;

分析一下,這樣實現的時間複雜度是 O(n) ,空間複雜度是 O(1)
和剛開始使用的方法相比,好了許多

你有沒有更巧妙的方法實現,歡迎評論區和我交流哇
最後,感謝您的閱讀~

相關文章