2021.10.22 力扣-每日一题-求众数 II

题目描述:

给定一个大小为 的整数数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素

方法一:

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
        int n = nums.size();
        vector<int> ans;
        int candidate1 = 0;     //候选者1
        int candidate2 = 0;     //候选者2
        int vote1 = 0;          //候选者1的票数
        int vote2 = 0;          //候选者2的票数
        for (int i = 0; i < n; i++)
        {
            //如果nums[i]是第一名候选者,其票数加一
            if (candidate1 == nums[i]) vote1++;
            //如果nums[i]是第二名候选者,其票数加一
            else if (candidate2 == nums[i]) vote2++;
            //如果原先的candidate1已经没票了,那么将nums[i]作为下一个候选者1
            else if (vote1 == 0)
            {
                candidate1 = nums[i];
                vote1++;
            }
            //如果原先的candidate2已经没票了,那么将nums[i]作为下一个候选者2
            else if (vote2 == 0)
            {
                candidate2 = nums[i];
                vote2++;
            }
            //否则,说明出现了三个不同的数字,相互抵消掉
            else
            {
                vote1--;
                vote2--;
            }
        }
        //接着统计candidate1和candidate2在数组中出现的次数
        int count1 = 0;
        int count2 = 0;
        for (int i = 0; i < n; i++)
        {
            if (nums[i] == candidate1)
            {
                count1++;
            }
            else if (nums[i] == candidate2)
            {
                count2++;
            }
        }
        if (vote1 > 0 && count1 > n / 3) ans.push_back(candidate1);
        if (vote2 > 0 && count2 > n / 3) ans.push_back(candidate2);
        return ans;
    }
};

暑假的时候曾做过【求众数】的第一道题,当时学习了题解所用的摩尔投票法,没想到这一方法还能够拓展到n / k的情况上去。

原本求众数时,即求数组中出现次数大于n / 2的数字,那么假设这个数字为X,可以将数组分为m个X一组,(n - m) 个其他数字一组,由于k > (n - m),所以若是将两两不同的数字相抵消,那么最终剩下的数字一定是X。

同理,若求数组中出现次数大于n / k的数字,那么只要每次将k个不同的数字相抵消,那么最终剩下的那些数字一定是出现次数大于n / k的那些数字。

于是这道题设有两个候选者,每遍历到一个数字,就考虑进行投票或者更换候选者或者抵消3个不同的数字。

注意第一次遍历完之后,还要再求一遍得到的候选者在数组中出现的次数是否大于n / 3,因为考虑一种特殊情况:数组只存在两种数字,那么由于不存在三个数字,所以没有抵消的情况出现,这时候是不能直接判断那种数字的出现次数大于n / 3的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值