摩尔投票法
不多说,先上题目。
问题描述:leetcode 229题
给定一个大小为 n 的整数数组,找出其中的所有的出现超过 ⌊ n/3 ⌋ 次的元素。
这还不简单!直接暴力计数,上map,easy搞定。
sorry!还有附加条件,忘记码上了>_<
设计时间复杂度为 O(n)、空间复杂度为 O(1)的算法解决此问题。
这下全了>^<如何解呢?空间复杂度O(n)怎么办?
别急,先来个中断,在小本本上记下,咱们先调用摩尔投票法。
摩尔投票法
又叫多数投票算法(Boyer–Moore majority vote algorithm)
出自这篇论文,有兴趣的小伙伴可以看看,锻炼英语。。
这里就用汉语描述一下主要内容。
- 算法描述
摩尔投票法,算法解决的问题是如何在任意多的候选人(选票无序),选出获得票数最多的那个。在无序且侯选人不定的情形,可运用摩尔投票法,投出一个主席,只要候选人的票数多余一半,就当选。
算法的比较次数最多是选票(记为n)的两倍,可以在 O(n)时间内选出获票最多的,空间开销为O(1)。
- 算法步骤
算法分为两个阶段:pairing阶段和counting阶段。
pairing阶段(抵消阶段):两个不同选票的人进行对抗,并会同时击倒对方,当剩下的人都是同一阵营,相同选票时,结束。
counting阶段(计数阶段):对最后剩下的下进行选票计算统计,判断选票是否超过总票数的一半,选票是否有效。
这里是我觉得讲的最清楚的算法步骤的一篇文章,没有之一,自愧不如,就分享来给大家看看。把候选人想成数组也太妙了。
怎么办还不懂?
看完一圈回来,相信大家都明白摩尔投票法是什么了。那最初这个题也会解了吧。
这里只给出C++的代码实现
class Solution {
public:
vector<int> majorityElement(vector<int>& nums) {
vector<int> ans;
if (nums.empty()) return ans;
int cand1, cand2;
int count1, count2;
cand1 = cand2 = count1 = count2 = 0;
// 抵消阶段
for (int i = 0; i < nums.size(); i++) {
if (nums[i] == cand1) count1++;
else if (nums[i] == cand2) count2++;
else if (count1 && count2) {
count1--;
count2--;
}
else if (!count1) {
cand1 = nums[i];
count1++;
}
else {
cand2 = nums[i];
count2++;
}
}
// 计数阶段
count1 = count2 = 0;
for (int i = 0; i < nums.size(); i++) {
if (nums[i] == cand1) count1++;
else if(nums[i] == cand2) count2++; // 必须用else if,保证每个数只算到一个候选人头上
else {}
}
if (count1 > nums.size() / 3) ans.push_back(cand1);
if (count2 > nums.size() / 3) ans.push_back(cand2);
return ans;
}
};
最后总结一下:
1.摩尔投票法的第一步pairing是用来在O(n)时间和O(1)空间内,选出众数来。
2.因为是选出众数,例如在[1,2,3]中,1或2或3都是众数,因此,还需要第二不counting重新再遍历一边,统计选出的的票数是否多余1/2。
3.由此可以推广,如果选出两名主席,则pairing步骤需要找出两个众数,counting需要检查,每个选出来个的主席是否票数都多余1/3。
如果要选出m名主席,要选出m个众的数,检查是否都多余1/(m+1)。
4.还有什么???没了。。。哦对!还有其他解法。
比如:哈希表方法和排序法找中位数(这个只使用选出一个主席的情况哦)
哈希map:
class Solution {
public:
int majorityElement(vector<int>& nums) {
unordered_map<int, int> counts;
int n = nums.size();
for (int i = 0; i < n; i++)
if (++counts[nums[i]] > n / 2)
return nums[i];
return 0;
}
};
排序:
int majorityElement(vector<int>& nums) {
sort(nums.begin(),nums.end());
return nums[nums.size() / 2];
}
参考文章
1.多数投票算法(Boyer-Moore Algorithm)详解
2.摩尔投票法(Boyer–Moore majority vote algorithm)
3.Boyer–Moore majority vote algorithm