开学回归力扣:第十二题—— 229. 求众数 II(摩尔投票法)

229. 求众数 II

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

进阶:尝试设计时间复杂度为 O(n)、空间复杂度为 O(1)的算法解决此问题。

示例 1:

输入:[3,2,3]
输出:[3]
示例 2:

输入:nums = [1]
输出:[1]
示例 3:

输入:[1,1,1,3,3,2,2,2]
输出:[1,2]
 

提示:

1 <= nums.length <= 5 * 104
-109 <= nums[i] <= 109

题解:

方法有三,前两种分别为遍历以及哈希表,这里不在赘述。

方法三:摩尔投票法

摩尔投票法就是适用于这种类似“选举”的问题,即求一堆数中个数最多的数的问题。
这里由于我们要找的“众数”个数最多为2个,所以我们按照两个“候选人”的方式进行查找。

首先明确摩尔投票法的本质是每三个不同的数字进行一次消除,即可以看做“消消乐”,根据本题限制可知,最后剩余的两个数字为这n个数字中的出现最多的数字

我们如何用代码来描述所谓的消除过程呢?
我们可以先选定两个初始的候选人A,B,然后对两个初始的候选人开始计数,如果下一个与A或B相同,那么给A或B自身加上一分,如果都不相同,那么观察一下此时的候选人A或B其分数是否为0,如果其中一个或都为0了,给其中一个更改候选人即可,另一个不变;如果此时A和B的分数都不为0,那么就视为此人投的为反对A和B的票(因为此时票的类型只有三种——投A,投B,反对A和B)。此行为也即模拟了所谓三个不同消除的动作
最后剩余的两个候选人为分最高的两个,但是他并不一定为票数超过n/3的人。
所以最后要加一个判断即可。

代码:

int* majorityElement(int* nums, int numsSize, int* returnSize){
    
    
    if(numsSize==1)
    {
    
    
        *returnSize = 1;
        return nums;
    }
    int*temp = (int*)malloc(sizeof(int)*2);
    int sco1 = 0;
    int sco2 = 0;
    temp[0] = nums[0];
    temp[1] = nums[0];
    for(int i=0;i<numsSize;i++)//默认在未计算票前候选人的分数为0时依然让他当候选人
    {
    
    
        if(nums[i]==temp[0])
        {
    
    
            sco1++;
            continue;
        }
        if(nums[i]==temp[1])
        {
    
    
            sco2++;
            continue;
        }
        if(sco1==0)//此过程即先判断是否有俩候选人的票,若没有则判断此时是否票为0,若是则开始更换候选人
        {
    
    
            temp[0] = nums[i];//候选人也会投票,但只有候选人票小于0时才会换人
            sco1++;//因为此时由于候选人的改变,票的性质发生了改变。且每个候选人本身也能参与投票,所以sco++
            continue;//跳过了,所以不会出现减票的了,此时票的性质也由两个人的“减”变成了一个人的“加”
        }
        if(sco2==0)
        {
    
    
            temp[1] = nums[i];
            sco2++;
            continue;
        }
        sco1--;
        sco2--;
    }
    int sum1 =0;
    int sum2 =0;
    for(int i=0;i<numsSize;i++)
    {
    
    
        if(nums[i]==temp[0])
        {
    
    
            sum1++;
            continue;
        }//设置continue,使得不会出现如[2,2]输出[2,2]的情况,因为前者会将后面的全部抢走完,不给后面的留
        if(nums[i]==temp[1])//即避免了重复的情况
        {
    
    
            sum2++;
            continue;
        }
    }
    if(sum1>numsSize/3&&sum2>numsSize/3)
    {
    
    
        *returnSize = 2;
        return temp;
    }
    else if(sum1>numsSize/3||sum2>numsSize/3)
    {
    
    
        *returnSize = 1;
        if(sum1>sum2)
        {
    
    
            return temp;
        }
        else
        {
    
    
            temp[0]=temp[1];
            return temp;
        }
    }
    *returnSize = 0;
    return temp;
}

猜你喜欢

转载自blog.csdn.net/xiangguang_fight/article/details/114839642
今日推荐