Majority Element II寻找主元素 II

一、概述

输入一个数组,找到它所有出现次数大于n/3的元素。

二、分析

不会。之前那个主元素的题忘记了。这次变种题就把我卡住了。
要求时间复杂度O(n)空间复杂度O(1),肯定不是哈希这种做法。
直接去看解析。
用的是摩尔投票法。上一道主元素题也是这样。它的具体思路是什么呢?按我的理解,就是找到当前以及之前所有元素中最大的元素。按该博客的说法,

数组中从candidate被赋值到count减到0的那一段可以被去除,余下部分的多数元素依然是原数组的多数元素。

这句话怎么理解呢?就是我们维护一个当前元素及所有之前元素的一个摘要,这个摘要记录了之前所有元素中数量最多的元素。之后就看这个摘要就行了,不用去管前面了。
这个算法核心就是形成摘要。以下面这个序列举例说明:
11132224444
本题要求我们找到的主元素要求是大于三分之一,那么最多有两个主元素。我们维护四个值:两个候选值m1和m2,它们的相对出现次数num1和num2,初始化为0。
首先读入第一个元素1,由于num1为0,因此令第一个候选值m1为1,num1为1;
接下来读入1,由于m1为1,因此num1加1,num1为2;
接下来读入1,由于m1为1,因此num1加1,num1为3;
接下来读入3,由于num2为0,因此令第二个候选值m2为3,num2为1;
接下来读入2,由于num1和num2均不为0,且2既不是m1也不是m2,因此令num1和num2都减1;
这一步之前,已经读入的序列为1113,m1=1,num1=3,m2=3,num2=1;这个摘要很好的描述了1113的性质;
这一步之后,已经读入的序列为11132,m1=1,num1=2,m2=3,num2=0;这个摘要很好的描述了11132的性质,因为出现了2,因此1和3的相对出现次数都减了1,11132的摘要可以是2个1,0个3,也就是11132可以直接看作是11;
接下来读入2,由于num2为0,因此m2变为2,num2为1;
接下来读入2,由于m2为2,因此num2加1,num2为2;
接下来读入4,由于num1和num2均不为0,且4既不是m1也不是m2,因此令num1和num2都减1,num1=1,num2=1,此时序列为11132224,之前压缩为1122,那么现在是11224,摘要为1个1,1个2;
接下来读入4,由于num1和num2均不为0,且4既不是m1也不是m2,因此令num1和num2都减1,num1=0,num2=0,此时序列为111322244,之前压缩为1122,那么现在是112244,摘要为0个1,0个2,看,现在1和2仍然是主元素候选;
接下来读入4,这时候,事情开始起变化。由于num1和num2均为0,且4既不是m1也不是m2,因此令m1为4,num1=1,此时序列为1113222444,之前压缩为1122,那么现在是1122444,摘要为1个4,0个2,看,现在4和2是主元素候选;
接下来读入4,由于m1为4,因此num1加一,num1为2;
最终的摘要为2个4,0个2。
这可以这样看:对于11132224444,首先把数量为1的3减去,压缩为11224444,然后把数量为2的1和2减去,压缩为44,这就是最终的摘要。
有的人可能要问,把数量为1的3减去这一步,为什么4不减去一个?根据上面的过程没有减,但实际减了也不影响结果。压缩为44或者压缩为4,最终主元素都是4,没有区别。
这就是摩尔投票法的总体思想。使用呢四个数来抽取前n个数的主元素信息。

三、总结

很著名的寻找主元素算法。这是其中一个变体。
PS:代码如下:

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
        int m1=0,m2=0,num1=0,num2=0,n=nums.size();
        for(auto i:nums)
        {
            if(i==m1)
                num1++;
            else if(i==m2)
                num2++;
            else if(num1==0)
            {
                m1=i;
                num1++;
            }
            else if(num2==0)
            {
                m2=i;
                num2++;
            }
            else
            {
                num1--;
                num2--;
            }
        }
        num1=0;
        num2=0;
        for(auto i:nums)
        {
            if(i==m1)
                num1++;
            if(i==m2)
                num2++;
        }
        vector<int> res;
        if(num1>n/3)
            res.push_back(m1);
        if(num2>n/3&&m1!=m2)
            res.push_back(m2);
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值