最近发现了一个比较有意思的选出众数的方法也就是摩尔投票法,据说最开始是出自某论文,不得不敬佩于写这篇论文人的智慧,所以想在此记录一下。
在此注明:摩尔投票法适用于众数在 在一堆数出现频率中超过一半的情况,如以下数:
2 2 1 1 1 2 2
可以看到一共7个数,其中2出现的频率出现了4次大于n/2,2就是我们要求的众数
摩尔投票法详细步骤如下:
1.初始选择数组中的第一个元素为我们的候选人,初始票为0
2.遍历数组
如果出现的数与候选人相同则票数加1
如果出现的数与候选人不相同且票数不为零则出现冲突,票数减一
如果出现的数与候选人票数不同且票数为零,则候选人替换为这个数,且票数加上1
3.遍历结束
废话不多说我们来看两个例子:
例1:leetcode-169多数元素
其实有很多方法去做,哈希,排序等但这个题其实就是使用摩尔排序法的经典例题,代码如下:
#include<iostream>
#include<vector>
#include<algorithm>
#include<unordered_map>
using namespace std;
class Solution {
public:
//摩尔投票法
int majorityElement(vector<int>& nums) {
int candidate = nums[0];
//选票
int count = 0;
for (int voter : nums) {
if (voter == candidate) {
count++;
}
else if(voter!=candidate&&count==0)
{
candidate = voter;
count++;
}
else if(voter!=candidate&&count!=0)
{
count--;
}
}
return candidate;
}
};
int main() {
vector<int> nums{ 2,2,1,1,1,2,2 };
Solution* st = new Solution();
cout << "众数为:" << st->majorityElement(nums) << endl;
}
读者按我上面的思路应该能读懂,运行结果如下:
为了让读者理解我画了个表格来描述这段代码的运行过程
再次提醒摩尔投票法只能适用于众数出现频率超过一半的情况下
当然这是摩尔投票法的简单运用,还可以有进阶版本
leetcode-229求众数2
题目描述如下:
注意这里是n/3,需要注意的是超过n/3其实最多只有两个,具体原因我想聪明的您应该是可以想通的。
我想说明的其实这个题仍可以用摩尔投票法,只不过有两个候选人和两种选票,代码如下:
#include<iostream>
#include<vector>
#include<algorithm>
#include<unordered_map>
using namespace std;
class Solution {
public:
//摩尔投票法
vector<int>majorityElement(vector<int>& nums) {
vector<int>vec;
int candidate1, candidate2;
candidate1 = nums[0];
candidate2 = nums[0];
int count1 = 0;
int count2 = 0;
/*
以下循环代码段为了找出两个候选人
*/
for (int temp : nums) {
if (temp == candidate1) {
count1++;
}
else if(temp==candidate2)
{
count2++;
}
else if(temp!=candidate1&&count1==0)
{
candidate1 = temp;
count1++;
}
else if(temp!=candidate2&&count2==0)
{
candidate2 = temp;
count2++;
}
else
{
count1--;
count2--;
}
}
/*
以下是为了验证确实最多只有两个超过n/3的众数,因为题中并没具体说明
*/
count1 = 0;
count2 = 0;
for (int elem : nums) {
if (elem == candidate1) {
count1++;
}
else if(elem==candidate2)
{
count2++;
}
}
if (count1 > nums.size() / 3) {
vec.push_back(candidate1);
count1++;
}
if (count2 > nums.size() / 3 && candidate1 != candidate2) {
vec.push_back(candidate2);
count2++;
}
return vec;
}
};
int main() {
vector<int> nums{ 1,1,1,3,3,2,2,2 };
vector<int>auxiliary;
Solution* st = new Solution();
//cout << "众数为:" << st->majorityElement(nums) << endl;
auxiliary = st->majorityElement(nums);
cout << "众数序列为:" << endl;
for (int elems : auxiliary) {
cout << elems << "\t";
}
cout << endl;
}
运行结果如下:
为了加深读者对代码的理解,我同样做了个表格表示代码的运行过程
希望可以加深读者的理解,按这么扩展我们可以使用摩尔投票法或者进阶摩尔投票法解决类似的求众数问题。
由于本人水平有限,可能会出现一些错误,欢迎各位指正。