引子
leetcode 169.多数元素
分析
1. 由于多数元素大于n / 2,所以多数元素至多一个且其一定为这个数组的众数,问题就转化成为了求一个数组的众数。
2. 求数组众数,为了使时间复杂度为O(n),我们可以很快想到空间复杂度O(n)的算法一:可以使用一个hash table来存储。
3. 为了降低空间复杂度为O(logn),我们也可以想到时间复杂度为O(nlogn)的排序算法二:先排序,结果中n / 2 就是众数。
3. 但是本题设置了空间复杂度为O(1),这样限定我们只能用有限的储存空间,这样我们也可以很快想到基于位运算的算法三:每一位计算一次为1的个数,如果大于n / 2就说明众数在这里为1,反之,为0,最后就可以拼接出结果。
4. 但是本题最优解是摩尔投票法。
摩尔投票法原理(简述)
最简单的理解:让数组中的数组进行厮杀,最后剩下的一定是众数。
算法步骤:
1. 两个变量,candidate记录候选众数,初始化为null,cnt记录厮杀结果初始化为0。
2. 从0 - n-1 开始遍历,如果cnt为0,表示candidate厮杀结束,需要将当前位置设置为candidate。
3. 最后剩下的candidate一定是众数。
算法原理:
详见:https://blog.csdn.net/happyeveryday62/article/details/104136295
证明:
假设共有n个代表(一人一票,选票总数为n)。当onwaier看到第i个代表的选票时( 1 ≤ i ≤ n ) (1 \leq i \leq n)(1≤i≤n),前面他已经看到的所有选票可以分为两组,第一组是k个代表赞同cand;另一组是选票可以全部成对(选票不同)抵销。当处理完所有的选票时,如果存在大多数,则cand当选。
假设存在一个x其不同于cand,但拥有的选票超过n / 2 n/2n/2。但因为第二组的选票可以全部成对抵销,所以x最多的选票数为( n − k ) / 2 (n - k) / 2(n−k)/2,因此x必须要收到第一组的选票才能超过一半,但是第一组的选票都是cand的,出现矛盾,假设不成立。
所以,如果存在大多数,cand就是那个。(注:如果不存在,cand不一定是众数。)
————————————————
版权声明:本文为CSDN博主「Onwaier」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/happyeveryday62/article/details/104136295
适用范围:
如果至多选一个代表,那他的票数至少要超过一半(⌊ 1/2 ⌋)的票数;
如果至多选两个代表,那他们的票数至少要超过 ⌊ 1/3 ⌋ 的票数;
如果至多选m个代表,那他们的票数至少要超过 ⌊ 1/(m+1) ⌋ 的票数。
题解:
class Solution {
public:
int majorityElement(vector<int>& nums) {
int cnt = 0, now = nums[0];
for (int i = 0; i < nums.size(); i++){
if(cnt == 0) now = nums[i];
if(now == nums[i]) cnt++;
else cnt--;
}
return now;
}
};