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;
}