LeetCode #229. Majority Element II 数组 摩尔投票法
Description
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]
思路
解法一
借鉴了#169 中的摩尔投票法,但是使用该算法的前提是数组必须存在一个 majorityElement 且它的出现频数大于数组元素数目的一半。因此,需要对该算法进行修改。
由题推得,任意一个数组出现次数大于 n/3 的数最多有两个,网上提供了证明:如果有超过两个,也就是至少三个数字满足“出现的次数大于 n/3”,那么就意味着数组里总共有超过 3*(n/3) = n 个数字,这与已知的数组大小矛盾,所以,只可能有两个或者更少。
原来的算法只是利用一个计数器,现在新增一个计数器,用两个计数器来统计出现次数大于 n/3 的数。
如果当前数字是这两个数中的一个,则对应计数器 + 1;
如果当时数字不是这两个数中的一个,则两个计数器都减一;
如果有一个计数器的值为 0 ,则该计数器重置为 1,用来统计当前数字的出现次数。
这三个判断必须以 if-else 方式执行,否则将不符合 Moore Voting 的思想。
由于之前 #169 中限定了一定会有大多数存在,故而当时省略了验证候选众数的步骤。但是这道题却没有这种限定,即满足要求的Majority Element可能不存在,所以要有验证步骤。
时间复杂度:O(n)
空间复杂度:O(1)
耗时 12 ms, Memory 8.5 MB, ranking 89.57%
class Solution {
public:
vector<int> majorityElement(const vector<int> &nums) {
if (nums.empty()) return {};
int mj1 = 0, mj2 = 0, cnt1 = 0, cnt2 = 0;
for (int element : nums) {
if (element == mj1) {
++cnt1;
} else if (element == mj2) {
++cnt2;
} else if (!cnt1) {
mj1 = element;
cnt1 = 1;
} else if (!cnt2) {
mj2 = element;
cnt2 = 1;
} else {
--cnt1;
--cnt2;
}
}
// recheck whether both mj1 and mj2 are majority element
cnt1 = 0, cnt2 = 0;
for (int element : nums) {
if (element == mj1) {
++cnt1;
continue; // mj1 != mj2, so don't need to judge next condition
}
if (element == mj2) {
++cnt2;
continue;
}
}
int len = nums.size()/3; // 2 = 8 / 3
if (cnt1 > len && cnt2 > len) {
return {mj1, mj2};
} else if (cnt1 > len) {
return {mj1};
} else if (cnt2 > len) {
return {mj2};
} else {
return {};
}
}
};
参考
- 《[LeetCode] 229. Majority Element II 求大多数之二》:https://www.cnblogs.com/grandyang/p/4606822.html
————全心全意投入,拒绝画地为牢