LeetCode----------------------求衆數

給定一個大小爲 的數組,找到其中的衆數。衆數是指在數組中出現次數大於 ⌊ n/2 ⌋ 的元素。

你可以假設數組是非空的,並且給定的數組總是存在衆數。

方法 1:哈希表
想法

可以用哈希表來快速統計每個元素出現的次數。

算法

我們使用哈希表來存儲每個元素,然後用一個循環在線性時間內遍歷 nums ,然後我們只需要返回有最大值的鍵。

class Solution {
    private Map<Integer, Integer> countNums(int[] nums) {
        Map<Integer, Integer> counts = new HashMap<Integer, Integer>();
        for (int num : nums) {
            if (!counts.containsKey(num)) {
                counts.put(num, 1);
            }
            else {
                counts.put(num, counts.get(num)+1);
            }
        }
        return counts;
    }

    public int majorityElement(int[] nums) {
        Map<Integer, Integer> counts = countNums(nums);

        Map.E***y<Integer, Integer> majorityE***y = null;
        for (Map.E***y<Integer, Integer> e***y : counts.e***ySet()) {
            if (majorityE***y == null || e***y.getValue() > majorityE***y.getValue()) {
                majorityE***y = e***y;
            }
        }

        return majorityE***y.getKey();
    }
}

複雜度分析

時間複雜度:O(n)

我們將 nums 迭代一次,哈希表的插入是常數時間的。所以總時間複雜度爲 O(n)O(n) 時間的。

空間複雜度:O(n)

方法 2:Boyer-Moore 投票算法
想法

如果我們把衆數記爲 +1+1 ,把其他數記爲 -1−1 ,將它們全部加起來,顯然和大於 0 ,從結果本身我們可以看出衆數比其他數多。

算法

本質上, Boyer-Moore 算法就是找 nums 的一個後綴 sufsuf ,其中 suf[0]suf[0] 就是後綴中的衆數。我們維護一個計數器,如果遇到一個我們目前的候選衆數,就將計數器加一,否則減一。只要計數器等於 0 ,我們就將 nums 中之前訪問的數字全部 忘記 ,並把下一個數字當做候選的衆數。直觀上這個算法不是特別明顯爲何是對的,我們先看下面這個例子(豎線用來劃分每次計數器歸零的情況)

[7, 7, 5, 7, 5, 1 | 5, 7 | 5, 5, 7, 7 | 7, 7, 7, 7]

首先,下標爲 0 的 7 被當做衆數的第一個候選。在下標爲 5 處,計數器會變回0 。所以下標爲 6 的 5 是下一個衆數的候選者。由於這個例子中 7 是真正的衆數,所以通過忽略掉前面的數字,我們忽略掉了同樣多數目的衆數和非衆數。因此, 7 仍然是剩下數字中的衆數。

[7, 7, 5, 7, 5, 1 | 5, 7 | 5, 5, 7, 7 | 5, 5, 5, 5]

現在,衆數是 5 (在計數器歸零的時候我們把候選從 7 變成了 5)。此時,我們的候選者並不是真正的衆數,但是我們在 遺忘 前面的數字的時候,要去掉相同數目的衆數和非衆數(如果遺忘更多的非衆數,會導致計數器變成負數)。

因此,上面的過程說明了我們可以放心地遺忘前面的數字,並繼續求解剩下數字中的衆數。最後,總有一個後綴滿足計數器是大於 0 的,此時這個後綴的衆數就是整個數組的衆數。

class Solution {
    public int majorityElement(int[] nums) {
        int count = 0;
        Integer candidate = null;

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

        return candidate;
    }
}

複雜度分析

時間複雜度:O(n)

Boyer-Moore 算法嚴格執行了 nn 次循環,所以時間複雜度是線性時間的。

空間複雜度:O(1)

Boyer-Moore 只需要常數級別的額外空間

作者:LeetCode
鏈接:https://leetcode-cn.com/problems/two-sum/solution/qiu-zhong-shu-by-leetcode-2/
來源:力扣(LeetCode)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章