leetcode打卡--moore投票法的运用详解

题目

摩尔投票概述

摩尔投票需要经过以下两个阶段:

  1. 抵消阶段
  2. 计数阶段

抵消阶段:两个不同投票进行对坑,并且同时抵消掉各一张票,如果两个投票相同,则累加可抵消的次数。

计数阶段:在抵消阶段最后得到的抵消计数只要不为 0,那这个候选人是有可能超过一半的票数的,为了验证,则需要遍历一次,统计票数,才可确定。

举个例子:在任意多的候选人中,选出票数超过⌊ 1/3 ⌋的候选人。

我们可以这样理解,假设投票是这样的 [A, B, C, A, A, B, C],ABC 是指三个候选人。

第 1 张票,第 2 张票和第3张票进行对坑,如果票都不同,则互相抵消掉;

第 4 张票,第 5 张票和第 6 张票进行对坑,如果有部分相同,则累计增加他们的可抵消票数,如 [A, 2] 和 [B, 1];

接着将 [A, 2] 和 [B, 1] 与第 7 张票进行对坑,如果票都没匹配上,则互相抵消掉,变成 [A, 1] 和 `[B, 0] 。

看下面动画,就知道什么回事了。

  1. 最多选取一个代表的过程:
  2. 最多选取两个代表的过程

动画转自leetcode。

总结归纳:

如果至多选一个代表,那他的票数至少要超过一半(⌊ 1/2 ⌋)的票数;

如果至多选两个代表,那他们的票数至少要超过 ⌊ 1/3 ⌋ 的票数;

如果至多选m个代表,那他们的票数至少要超过 ⌊ 1/(m+1) ⌋ 的票数。

所以以后碰到这样的问题,而且要求达到线性的时间复杂度以及常量级的空间复杂度,直接套上摩尔投票法。

解题过程

  • 由于是选出两个代表的问题,也就是选出票数超过 1/3 的个数。

有以下两种做法:

  1. 哈希表
  2. 摩尔投票法

解题代码

哈希表法

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
        unordered_map<int,int>check;
        int c = nums.size()/3;
        unordered_set<int>tt;
        for(auto&& t : nums){
            check[t]++;
            if(check[t]>c){
                tt.insert(t);
            }
        }
        vector<int>res(tt.begin(),tt.end());
    return res;
    }
};

摩尔投票法

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
        int n = nums.size();
        vector<int>res;
        if(n<3){
            unordered_set<int> t(nums.begin(),nums.end());
            return vector<int>(t.begin(),t.end());
        }
        int candidate1 = nums[0],candidate2 = nums[1],cnt1 = 0,cnt2 = 0;
        for(auto&& t:nums){//投票过程
            if(t==candidate1){
                cnt1++;
                continue;
            }
            if(t==candidate2){
                cnt2++;
                continue;
            }
            if(cnt1==0){
                candidate1 = t;
                cnt1++;
                continue;
            }
            if(cnt2==0){
                candidate2 = t;
                cnt2++;
                continue;
            }
            cnt1--;
            cnt2--;
        }
    int _cnt1 = 0,_cnt2 = 0;
    for(auto&&t:nums){_cnt1 += candidate1==t?1:0;}//计数过程
    for(auto&&t:nums){_cnt2 += candidate2==t?1:0;}
    if(_cnt1>n/3)res.push_back(candidate1);
    if(_cnt2>n/3){
        if(res.empty())
            res.push_back(candidate2);
        else{
            if(candidate2!=candidate1)
                res.push_back(candidate2);
        }
    }
    return res;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值