1. 程式人生 > 其它 >統計一批學生的平均成績與不及格人數

統計一批學生的平均成績與不及格人數

目錄

229. 求眾數 II

思路

方法一:雜湊統計

用雜湊統計陣列中每個元素出現的次數。

方法二:摩爾投票法

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

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

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

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

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

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

本題是在任意多的候選人中,選出票數超過⌊ 1/3 ⌋的候選人。可以這樣理解,假設投票是這樣的 [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;
    }
}