文章目錄
- 題目
- 標題和出處
- 難度
- 題目描述
- 要求
- 示例
- 數據范圍
- 進階
- 前言
- 解法一
- 思路和算法
- 代碼
- 復雜度分析
- 解法二
- 思路和算法
- 代碼
- 復雜度分析
- 解法三
- 思路和算法
- 代碼
- 復雜度分析
題目
標題和出處
標題:多數元素 II
出處:229. 多數元素 II
難度
3 級
題目描述
要求
給定大小為 n \texttt{n} n 的數組 nums \texttt{nums} nums,找出其中所有出現超過 ? n 3 ? \Big\lfloor \dfrac{\texttt{n}}{\texttt{3}} \Big\rfloor ?3n?? 次的元素。
示例
示例 1:
輸入: nums = [3,2,3] \texttt{nums = [3,2,3]} nums?=?[3,2,3]
輸出: [3] \texttt{[3]} [3]
示例 2:
輸入: nums = [1] \texttt{nums = [1]} nums?=?[1]
輸出: [1] \texttt{[1]} [1]
示例 3:
輸入: nums = [1,2] \texttt{nums = [1,2]} nums?=?[1,2]
輸出: [1,2] \texttt{[1,2]} [1,2]
數據范圍
- n = nums.length \texttt{n} = \texttt{nums.length} n=nums.length
- 1 ≤ n ≤ 5 × 10 4 \texttt{1} \le \texttt{n} \le \texttt{5} \times \texttt{10}^\texttt{4} 1≤n≤5×104
- -10 9 ≤ nums[i] ≤ 10 9 \texttt{-10}^\texttt{9} \le \texttt{nums[i]} \le \texttt{10}^\texttt{9} -109≤nums[i]≤109
進階
你可以使用線性時間復雜度和 O(1) \texttt{O(1)} O(1) 空間復雜度解決此問題嗎?
前言
這道題是「多數元素」的進階,要求找出數組中所有出現次數大于 ? n 3 ? \Big\lfloor \dfrac{n}{3} \Big\rfloor ?3n?? 的元素。這道題也可以使用哈希表計數、排序和摩爾投票三種解法得到答案。
長度是 n n n 的數組中,最多有 2 2 2 個出現次數大于 ? n 3 ? \Big\lfloor \dfrac{n}{3} \Big\rfloor ?3n?? 的元素。可以使用反證法證明。
假設有 3 3 3 個出現次數大于 ? n 3 ? \Big\lfloor \dfrac{n}{3} \Big\rfloor ?3n?? 的元素,這 3 3 3 個元素的出現次數都不小于 ? n 3 ? + 1 \Big\lfloor \dfrac{n}{3} \Big\rfloor + 1 ?3n??+1,因此這 3 3 3 個元素的總出現次數至少為 3 × ? n 3 ? + 3 3 \times \Big\lfloor \dfrac{n}{3} \Big\rfloor + 3 3×?3n??+3。由于 ? n 3 ? > n 3 ? 1 \Big\lfloor \dfrac{n}{3} \Big\rfloor > \dfrac{n}{3} - 1 ?3n??>3n??1,因此 3 × ? n 3 ? + 3 > 3 × ( n 3 ? 1 ) + 3 = 3 × n 3 ? 3 + 3 = n 3 \times \Big\lfloor \dfrac{n}{3} \Big\rfloor + 3 > 3 \times (\dfrac{n}{3} - 1) + 3 = 3 \times \dfrac{n}{3} - 3 + 3 = n 3×?3n??+3>3×(3n??1)+3=3×3n??3+3=n,即這 3 3 3 個元素的總出現次數一定超過 n n n,和數組長度是 n n n 矛盾。因此數組中不可能有 3 3 3 個出現次數大于 ? n 3 ? \Big\lfloor \dfrac{n}{3} \Big\rfloor ?3n?? 的元素,最多有 2 2 2 個出現次數大于 ? n 3 ? \Big\lfloor \dfrac{n}{3} \Big\rfloor ?3n?? 的元素。
解法一
思路和算法
最直觀的解法是統計數組中每個元素的出現次數,然后尋找出現次數大于 ? n 3 ? \Big\lfloor \dfrac{n}{3} \Big\rfloor ?3n?? 的元素。
遍歷數組,使用哈希表記錄每個元素的出現次數,遍歷結束之后即可得到數組中每個元素的出現次數。然后遍歷哈希表,對于哈希表中的每個元素得到出現次數,將出現次數大于 ? n 3 ? \Big\lfloor \dfrac{n}{3} \Big\rfloor ?3n?? 的元素添加到結果中。
代碼
class Solution {public List<Integer> majorityElement(int[] nums) {Map<Integer, Integer> counts = new HashMap<Integer, Integer>();for (int num : nums) {counts.put(num, counts.getOrDefault(num, 0) + 1);}List<Integer> majorities = new ArrayList<Integer>();int n = nums.length;Set<Integer> set = counts.keySet();for (int num : set) {if (counts.get(num) > n / 3) {majorities.add(num);}}return majorities;}
}
復雜度分析
-
時間復雜度: O ( n ) O(n) O(n),其中 n n n 是數組 nums \textit{nums} nums 的長度。遍歷數組統計每個元素的出現次數需要 O ( n ) O(n) O(n) 的時間,遍歷哈希表得到多數元素也需要 O ( n ) O(n) O(n) 的時間。
-
空間復雜度: O ( n ) O(n) O(n),其中 n n n 是數組 nums \textit{nums} nums 的長度。需要創建哈希表記錄每個元素的出現次數,哈希表中的元素個數不超過 n n n。
解法二
思路和算法
首先將數組排序,排序后的數組滿足相等的元素一定出現在數組中的相鄰位置。如果一個元素在數組中的出現次數大于 ? n 3 ? \Big\lfloor \dfrac{n}{3} \Big\rfloor ?3n??,則排序后的數組中存在至少 ? n 3 ? + 1 \Big\lfloor \dfrac{n}{3} \Big\rfloor + 1 ?3n??+1 個連續的元素都等于該元素,即一定存在兩個差為 ? n 3 ? \Big\lfloor \dfrac{n}{3} \Big\rfloor ?3n?? 的下標處的元素都等于該元素。
將數組 nums \textit{nums} nums 排序之后遍歷數組 nums \textit{nums} nums,對于下標 i i i,當 i ≥ ? n 3 ? i \ge \Big\lfloor \dfrac{n}{3} \Big\rfloor i≥?3n?? 時,如果 nums [ i ] = nums [ i ? ? n 3 ? ] \textit{nums}[i] = \textit{nums}[i - \Big\lfloor \dfrac{n}{3} \Big\rfloor] nums[i]=nums[i??3n??],則 nums [ i ] \textit{nums}[i] nums[i] 是出現次數大于 ? n 3 ? \Big\lfloor \dfrac{n}{3} \Big\rfloor ?3n?? 的元素。
為了避免重復計算,當 i < n ? 1 i < n - 1 i<n?1 且 nums [ i ] = nums [ i + 1 ] \textit{nums}[i] = \textit{nums}[i + 1] nums[i]=nums[i+1] 時跳過下標 i i i,只有當下標 i i i 的右側沒有與 nums [ i ] \textit{nums}[i] nums[i] 相等的元素時才判斷 nums [ i ] = nums [ i ? ? n 3 ? ] \textit{nums}[i] = \textit{nums}[i - \Big\lfloor \dfrac{n}{3} \Big\rfloor] nums[i]=nums[i??3n??] 是否成立,如果成立則將 nums [ i ] \textit{nums}[i] nums[i] 添加到結果中。
代碼
class Solution {public List<Integer> majorityElement(int[] nums) {Arrays.sort(nums);List<Integer> majorities = new ArrayList<Integer>();int n = nums.length;for (int i = n / 3; i < n; i++) {int num = nums[i];if (i < n - 1 && num == nums[i + 1]) {continue;}if (num == nums[i - n / 3]) {majorities.add(num);}}return majorities;}
}
復雜度分析
-
時間復雜度: O ( n log ? n ) O(n \log n) O(nlogn),其中 n n n 是數組 nums \textit{nums} nums 的長度。排序需要 O ( n log ? n ) O(n \log n) O(nlogn) 的時間。
-
空間復雜度: O ( log ? n ) O(\log n) O(logn),其中 n n n 是數組 nums \textit{nums} nums 的長度。排序需要 O ( log ? n ) O(\log n) O(logn) 的遞歸調用棧空間。
解法三
思路和算法
原始的摩爾投票算法用于找到出現次數大于一半的元素,其時間復雜度是 O ( n ) O(n) O(n),空間復雜度是 O ( 1 ) O(1) O(1)。摩爾投票算法可以推廣到尋找出現次數大于 ? n k ? \Big\lfloor \dfrac{n}{k} \Big\rfloor ?kn?? 的元素,其中 k k k 是大于 1 1 1 的正整數。
由于出現次數大于 ? n 3 ? \Big\lfloor \dfrac{n}{3} \Big\rfloor ?3n?? 的元素不可能超過 2 2 2 個,因此維護 2 2 2 個候選元素 majority 1 \textit{majority}_1 majority1? 和 majority 2 \textit{majority}_2 majority2?,以及兩個候選元素的出現次數 count 1 \textit{count}_1 count1? 和 count 2 \textit{count}_2 count2?,初始時候選元素和出現次數都是 0 0 0。
遍歷數組,當遍歷到元素 num \textit{num} num 時,執行如下操作。
-
比較 num \textit{num} num 是否和候選元素相等,如果相等則將相應的出現次數加 1 1 1。
-
如果 num = majority 1 \textit{num} = \textit{majority}_1 num=majority1?,則將 count 1 \textit{count}_1 count1? 加 1 1 1。
-
否則,如果 num = majority 2 \textit{num} = \textit{majority}_2 num=majority2?,則將 count 2 \textit{count}_2 count2? 加 1 1 1。
-
-
如果 num \textit{num} num 和兩個候選元素都不相等,則判斷兩個候選元素的出現次數是否為 0 0 0,如果為 0 0 0 則更新候選元素和出現次數。
-
如果 count 1 = 0 \textit{count}_1 = 0 count1?=0,則將 majority 1 \textit{majority}_1 majority1? 更新為 num \textit{num} num,并將 count 1 \textit{count}_1 count1? 加 1 1 1。
-
否則,如果 count 2 = 0 \textit{count}_2 = 0 count2?=0,則將 majority 2 \textit{majority}_2 majority2? 更新為 num \textit{num} num,并將 count 2 \textit{count}_2 count2? 加 1 1 1。
-
-
如果 num \textit{num} num 和兩個候選元素都不相等且兩個候選元素的出現次數都大于 0 0 0,則 num \textit{num} num 和兩個候選元素抵消,將 count 1 \textit{count}_1 count1? 和 count 2 \textit{count}_2 count2? 都減 1 1 1。
遍歷結束之后,得到兩個候選元素。再次遍歷數組,統計兩個候選元素在數組中的出現次數,當出現次數大于 ? n 3 ? \Big\lfloor \dfrac{n}{3} \Big\rfloor ?3n?? 時將候選元素添加到結果中。
代碼
class Solution {public List<Integer> majorityElement(int[] nums) {int majority1 = 0, majority2 = 0;int count1 = 0, count2 = 0;for (int num : nums) {if (num == majority1) {count1++;} else if (num == majority2) {count2++;} else if (count1 == 0) {majority1 = num;count1++;} else if (count2 == 0) {majority2 = num;count2++;} else {count1--;count2--;}}count1 = 0;count2 = 0;for (int num : nums) {if (num == majority1) {count1++;} else if (num == majority2) {count2++;}}List<Integer> majorities = new ArrayList<Integer>();int n = nums.length;if (count1 > n / 3) {majorities.add(majority1);}if (count2 > n / 3) {majorities.add(majority2);}return majorities;}
}
復雜度分析
-
時間復雜度: O ( n ) O(n) O(n),其中 n n n 是數組 nums \textit{nums} nums 的長度。需要遍歷數組 nums \textit{nums} nums 兩次。
-
空間復雜度: O ( 1 ) O(1) O(1)。