摩爾投票法


229. 求眾數 II

思路

方法一:哈希統計

用哈希統計數組中每個元素出現的次數。

方法二:摩爾投票法

摩爾投票法:摩爾投票法的核心思想為對拼消耗。首先我們考慮最基本的摩爾投票問題,比如找出一組數字序列中出現次數大於總數一半的數字(並且假設這個數字一定存在)。我們可以直接利用反證法證明這樣的數字只可能有一個。

假設投票是這樣的,[A, C, A, A, B],ABC 是指三個候選人。

  • 第一張票與第二張票進行對坑,如果票不同則互相抵消掉;
  • 接着第三票與第四票進行對坑,如果票相同,則增加這個候選人的可抵消票數;
  • 這個候選人拿着可抵消票數與第五張票對坑,如果票不同,則互相抵消掉,即候選人的可抵消票數 -1。

摩爾投票法分為兩個階段:抵消階段和計數階段。

  • 抵消階段:兩個不同投票進行對坑,並且同時抵消掉各一張票,如果兩個投票相同,則累加可抵消的次數;
  • 計數階段:在抵消階段最后得到的抵消計數只要不為 0,那這個候選人是有可能超過一半的票數的,為了驗證,則需要遍歷一次,統計票數,才可確定。

摩爾投票法經歷兩個階段最多消耗 O(2n) 的時間,也屬於 O(n) 的線性時間復雜度,另外空間復雜度也達到常量級。

本題是在任意多的候選人中,選出票數超過⌊ 1/3 ⌋的候選人。
這意味着最多只能有兩位候選人,反證:若候選人數m>2,則 由每名候選人的最小票數 x>n/3,求和得候選人總票數>mx>3n/3=n,即候選人的總票數超過了所有投票數,矛盾。
可以這樣理解,假設投票是這樣的 [A, B, C, A, A, B, C],ABC 是指三個候選人。

  • 第 1 張票,第 2 張票和第3張票進行對坑,如果票都不同,則互相抵消掉;
  • 第 4 張票,第 5 張票和第 6 張票進行對坑,如果有部分相同,則累計增加他們的可抵消票數,如 [A, 2] 和 [B, 1];
  • 接着將 [A, 2] 和 [B, 1] 與第 7 張票進行對坑,如果票都沒匹配上,則互相抵消掉,變成 [A, 1] 和 [B, 0] 。

代碼

class Solution {
    public List<Integer> majorityElement(int[] nums) {
        // 創建返回值
        List<Integer> res = new ArrayList<>();
        if (nums == null || nums.length == 0) return res;
        // 初始化兩個候選人candidate,和他們的計票
        int cand1 = nums[0], count1 = 0;
        int cand2 = nums[0], count2 = 0;

        // 摩爾投票法,分為兩個階段:配對階段和計數階段
        // 配對階段
        for (int num : nums) {
            // 投票
            if (cand1 == num) {
                count1++;
                continue;
            }
            if (cand2 == num) {
                count2++;
                continue;
            }

            // 第1個候選人配對
            if (count1 == 0) {
                cand1 = num;
                count1++;
                continue;
            }
            // 第2個候選人配對
            if (count2 == 0) {
                cand2 = num;
                count2++;
                continue;
            }

            count1--;
            count2--;
        }

        // 計數階段
        // 找到了兩個候選人之后,需要確定票數是否滿足大於 N/3
        count1 = 0;
        count2 = 0;
        for (int num : nums) {
            if (cand1 == num) count1++;
            else if (cand2 == num) count2++;
        }

        if (count1 > nums.length / 3) res.add(cand1);
        if (count2 > nums.length / 3) res.add(cand2);

        return res;
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM