Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times.
Note: The algorithm should run in linear time and in O(1) space.
Example 1:
Input: [3,2,3] Output: [3]
Example 2:
Input: [1,1,1,3,3,2,2,2] Output: [1,2]
這道題讓我們求出現次數大於 n/3 的數字,而且限定了時間和空間復雜度,那么就不能排序,也不能使用 HashMap,這么苛刻的限制條件只有一種方法能解了,那就是摩爾投票法 Moore Voting,這種方法在之前那道題 Majority Element 中也使用了。題目中給了一條很重要的提示,讓先考慮可能會有多少個這樣的數字,經過舉了很多例子分析得出,任意一個數組出現次數大於 n/3 的數最多有兩個,具體的證明博主就不會了,博主也不是數學專業的(熱心網友用手走路提供了證明:如果有超過兩個,也就是至少三個數字滿足“出現的次數大於 n/3”,那么就意味着數組里總共有超過 3*(n/3) = n 個數字,這與已知的數組大小矛盾,所以,只可能有兩個或者更少)。那么有了這個信息,使用投票法的核心是找出兩個候選數進行投票,需要兩遍遍歷,第一遍歷找出兩個候選數,第二遍遍歷重新投票驗證這兩個候選數是否為符合題意的數即可,選候選數方法和前面那篇 Majority Element 一樣,由於之前那題題目中限定了一定會有大多數存在,故而省略了驗證候選眾數的步驟,這道題卻沒有這種限定,即滿足要求的大多數可能不存在,所以要有驗證,參加代碼如下:
class Solution { public: vector<int> majorityElement(vector<int>& nums) { vector<int> res; int a = 0, b = 0, cnt1 = 0, cnt2 = 0, n = nums.size(); for (int num : nums) { if (num == a) ++cnt1; else if (num == b) ++cnt2; else if (cnt1 == 0) { a = num; cnt1 = 1; } else if (cnt2 == 0) { b = num; cnt2 = 1; } else { --cnt1; --cnt2; } } cnt1 = cnt2 = 0; for (int num : nums) { if (num == a) ++cnt1; else if (num == b) ++cnt2; } if (cnt1 > n / 3) res.push_back(a); if (cnt2 > n / 3) res.push_back(b); return res; } };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/229
類似題目:
Check If a Number Is Majority Element in a Sorted Array
參考資料:
https://leetcode.com/problems/majority-element-ii/
