229. 求众数 II
题目描述
给定一个大小为 n 的数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。说明: 要求算法的时间复杂度为 O(n),空间复杂度为 O(1)。
示例 1:
输入: [3,2,3]
输出: [3]
示例 2:
输入: [1,1,1,3,3,2,2,2]
输出: [1,2]
提示1:
How many majority elements could it possibly have?
Do you have a better hint? Suggest it!
思路
两道众数题,解法的核心思想是:去掉两个不同的数(求大于⌊n/2⌋的元素)或者三个不同的数(求超过⌊n/3⌋次的元素)是不会改变最终要求的结果众数的
A,B,C
需要注意的是,这里的抵消需要一起进行,完成一次抵消操作一定去除的是三个完全不同的数,如果不满足这个条件,是不会触发抵消操作的
这种解法的正确性我们依然可以按照反证法进行论证
代码实现
class Solution {
public:
vector<int> majorityElement(vector<int>& nums) {
int n = nums.size();
vector<int> ret;
if(n == 0)
return ret;
int x = -1;
int cnt1 = 0;
int y = -1;
int cnt2 = 0;
for(int i = 0;i < n;i++)//流式处理
{
//num[i]是否分配给x
if((cnt1==0 && (cnt2==0 || nums[i]!=y)) || (cnt1!=0 && nums[i]==x))//只能分配给x
{
x = nums[i];
cnt1++;
continue;
}
//程序到达这里,说明针对本轮的新样本num[i],x不满足计数值增加的条件
//num[i]是否分配给y
if((cnt2==0 && (cnt1==0 || nums[i]!=x)) || (cnt2!=0 && nums[i]==y))//只能分配给y
{
y = nums[i];
cnt2++;
continue;
}
//程序到达这里,说明针对本轮的新样本num[i],y不满足计数值增加的条件
//到达这里说明num[i]既不能分配给x,也不能分配给y,只能独立成为一个实体,
//与x,y,num[i]这三个不同的数发生抵消,去掉
cnt1--;
cnt2--;
}
if(cnt1)
{
int cnt = 0;
for(int i = 0;i < n;i++)
{
if(nums[i] == x)
cnt++;
}
if(cnt > n/3)
ret.push_back(x);
}
if(cnt2)
{
int cnt = 0;
for(int i = 0;i < n;i++)
{
if(nums[i] == y)
cnt++;
}
if(cnt > n/3)
ret.push_back(y);
}
return ret;
}
};