LeetCode第 229 题:求众数 II(C++)

229. 求众数 II - 力扣(LeetCode)

LeetCode第 169 题:多数元素(C++)_zj-CSDN博客的进阶

哈希表

就不贴代码了,计数就可以了

摩尔投票法

题目并没有保证一定会有一个元素出现次数在n/3以上。

n/k的众数最多只有k-1个,也就是这题结果可能为一个数或者两个数,或者不存在。

可以看这个解释:从柱形图角度超极速理解,为什么摩尔投票法适用于任意多个候选人 - 求众数 II - 力扣(LeetCode)

在这里插入图片描述

我们要先找到出现次数最多的两个数,然后检查这两个数是否符合要求。

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
        vector<int> res;
        if(nums.size() == 0)    return res;
        int cand1 = 0, cand2 = 0;//两个候选
        int cnt1 = 0, cnt2 = 0;//计数
        for(auto num : nums){
            if(num == cand1){// 如果是候选者1,票数++
                ++cnt1;
                continue;
            } 
            if(num == cand2){// 如果是候选者2,票数++
                ++cnt2;
                continue;
            } 
            if(cnt1 == 0){// 既不是cand1也不是cand2,如果cnt1为0,那它就去做cand1
                cand1 = num;
                ++cnt1;
                continue;
            }
            if(cnt2 == 0){// cand1的cnt1不为0但是cand2的cnt2为0,那他就去做cand2
                cand2 = num;
                ++cnt2;
                continue;
            }
            // 如果cand1和cand2的数量都不为0,那就都-1
            --cnt1;
            --cnt2;
        }
        cnt1 = cnt2 = 0;
        //还需要检查两个候选者的票数是否真的大于n/3
        for(const auto &num : nums){
            if(num == cand1)    ++cnt1;
            else if(num == cand2)   ++cnt2;//用else if是为了防止初始值的设定刚好是等于某个元素,比如[0,0,0]这种特例
        }
        if(cnt1 > nums.size()/3)    res.push_back(cand1);
        if(cnt2 > nums.size()/3)    res.push_back(cand2);
        return res;
    }
};

摩尔投票法(另一个思路)

最多会有两个元素。

之前的题目我们是通过加1,减1计数的,这儿换个思路。

如果元素a的个数大于总个数的1/3,我们每次遍历碰到这个数就+2,碰到的不是这个数就-1,遍历结束之后我们就能找到这个元素a(会有特殊情况,代码里考虑)。

再考虑除去这个元素的数组,如果剩下的元素里面还有一个元素b出现次数符合要求,那么它在出去元素a的数组里的占比肯定大于1//2,那这不就是169题简单版的摩尔投票吗?就再投一次就可以了。

需要注意的是,题目没有保证目标元素一定会出现,所以每次投票完都需要进行检查。

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
        vector<int> res;
        int num1, cnt = 0;
        for(const auto &num : nums){
            if(cnt == 0) num1 = num;
            cnt += num1 == num ? 2 : -1;
        }
        cnt = 0;
        for(const auto &num : nums){
            if(num == num1) ++cnt;
        }
        if(cnt > nums.size()/3) res.push_back(num1);
        //else return res;//这儿不能直接return,因为[6,5,5]这种目标数字在最后一位的,可能会找不到

        //考虑出去num1之后的数组
        int num2;
        cnt = 0;
        for(const auto &num : nums){
            if(num == num1) continue;
            if(cnt == 0)   num2 = num;
            cnt += num2 == num ? 1 : -1;
        }

        cnt = 0;
        for(const auto &num : nums){
            if(num == num2) ++cnt;
        }
        if(cnt > nums.size()/3) res.push_back(num2);
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值