摩尔投票算法
摩尔投票算法
顾名思义是一种类似投票过程的算法
其由1981年出版的Robert S. Boyer和J Strother Moore的名字命名,并且是流式算法的典型例子。
LeedCode原题:
给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋
的元素。
你可以假设数组是非空的,并且给定的数组总是存在众数。
易知事实:由于假定总是存在众数,那么每个数组有且仅有一个众数
证明:假设存在两个众数,且每个出现次数都大于 ⌊ n/2 ⌋
,那么元素个数将超过n,不符合已知条件。因此有且仅有一个众数
基于此事实:
摩尔投票算法每次从序列里选择两个不相同的数字删除掉(或称为“抵消”),最后剩下一个数字或几个相同的数字,就是出现次数大于总数一半的那个。(众数个数大于其他各种元素个数,故最后剩下一个或几个相同的数字为众数)
同时证明最终不会一个数字都不剩:
无论n为奇数还是偶数,众数的个数总是比其他元素的总和多1,无论如何消除,最后不会为空。
那么具体如何求一个数组的众数呢?参考知乎
按常理我们队数组中每种元素进行出现次数的统计,超过 ⌊ n/2 ⌋的元素则为众数。
然而其核心就是对拼消耗。
类似玩一个诸侯争霸的游戏,假设你方人口超过总人口一半以上,并且能保证每个人口出去干仗都能一对一同归于尽。
最后还有人活下来的国家就是胜利。
因此不断地从数组中删除两个不同的元素,最后剩下来的一定是众数。
那么众数在数组中的顺序是否影响结果呢?答案是不会影响。
将元素的个数多少理解为打架拼人头的优势,前面删除的元素类似于已经互殴被打死了,对后面的战斗不增加优势。因此主要看拼到最后谁还有人头优势。即为众数。人多势重。
解答:
int majorityElement(int* nums, int numsSize){
int major=nums[0];
int count=1;
for(int i=1;i<numsSize;i++)
{
if(count==0)
major=nums[i];
if(nums[i]==major)
count++;
else
count--;
}
return major;
}
摩尔投票算法的改进
给定一个整型数组,找到所有主元素,它在数组中的出现次数严格大于数组元素个数的三分之一。
算法:每次删除三个不相同的数,最后留下的一定是出现次数超过1/3的数,这个思想可以推广到出现次数超过1/k次的元素有哪些。
因为出现次数大于n/3的元素最多只有两个,所以最开始可以维护两个数字(num1,num2)和两个计数器(counter1,counter2);
遍历数组,当数组中元素和num1或者num2相同,对应的counter1或者counter2加1;
如果counter1或counter2为0,将遍历到的该元素赋给num1或者nums2;
否则counter1和counter2都减1。