leetcode-每日一题2021.10.22 229. 求众数 II

题目

力扣

思路一 哈希表

用一个哈希表存储数组中元素出现的次数,最后判断大于n/3的就放入要返回的vector中。

代码一

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
        vector<int> ret;
        unordered_map<int,int> cnt;
        int n=nums.size();
        for(int num:nums)
            cnt[num]++;
        for(auto v:cnt){
            if(v.second>n/3)
                ret.push_back(v.first);
        }
        return ret;
    }
};

思路二 摩尔投票

摩尔投票法分为两个阶段:抵消阶段和计数阶段。

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

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

摩尔投票法经历两个阶段最多消耗 O(2n)的时间,也属于 O(n) 的线性时间复杂度,另外空间复杂度也达到常量级。

归纳:

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

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

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

一个很好的理解:摩尔投票就是一个消消乐游戏,每次消除3个不同的数。因为我们想要的结果至少获得了 ⌊ 1/3 ⌋的票数,那么它一定没有被完全消除。通过消消乐可以缩小候选人的寻找范围。要验证结果就遍历一遍计算票数就好了。

对于这一道题,设置两个候选人和两个计数值。依然是有抵消和计数两个阶段。抵消阶段,先找到两个不同的候选人,再往后遍历。如果当前数能匹配到候选人,就给计数值加一。如果匹配不到,判断当前两个候选人的计数值。如果计数值都大于0,就将计数值减一;如果有一个计数值为0,就把这个候选人换掉,这个计数值改为1.

代码二

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
        int cand1,cand2,cnt1,cnt2,n=nums.size();
        //初始候选人任意,因为cnt为0会更新
        cand1=cand2=cnt1=cnt2=0;
        for(int num:nums){
            if(num==cand1){
                cnt1++;
            }else if(num==cand2){
                cnt2++;
            }else if(cnt1&&cnt2){
                cnt1--;
                cnt2--;
            }else if(!cnt1){
                cand1=num;
                cnt1=1;
            }else if(!cnt2){
                cand2=num;
                cnt2=1;
            }
        }

        //遍历判断结果是否正确
        cnt1=cnt2=0;
        for(int num:nums){
            if(num==cand1)
                cnt1++;
            else if(num==cand2)
                cnt2++;
        }
        vector<int> v;
        if(cnt1>n/3) v.push_back(cand1);
        if(cnt2>n/3) v.push_back(cand2);
        return v;
    }
};

ps.如果是找出现次数大于n/2的数,还可以通过排序,中位数就是中间的元素。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值