例:169. 多数元素 - 力扣(LeetCode) (leetcode-cn.com)
题目:找出一个数组中出现次数超过一半的数字。
摩尔投票法可以使用 O(n) 的时间复杂度和常数的空间解决这个问题。
把出现次数超过一半的数字定义为多数元素
首先维护一个变量,和它的票数,假设它就是答案,遍历数组,如果当前的数和维护的值相同,就为它的票数加一,否则减一,当票数减到0的时候就更新这个变量为当前值,在保证存在多数元素的情况下,遍历到最后时剩下的数一定为这个数组中多数元素。
这个算法的原理可以看作每次取出两个不同的数消掉,最后剩下的自然就是多数元素。
int n = nums.size() , t = nums[0] , cnt = 1;
for(int i =1;i<n;i++)
{
if(nums[i]==t)cnt++;
else cnt--;
if(cnt==0)t = nums[i],cnt = 1;
}
进阶:229. 求众数 II - 力扣(LeetCode) (leetcode-cn.com)
找出一个数组中所有出现次数超过 ⌊ n/3 ⌋ 的数字。
和上面的类似,出现次数超过 ⌊ n/3 ⌋ 的数字最多为两个,,所以变为维护两个数即可,要注意在之后检查一遍是否满足以及是否相等。
索性直接写一个:⌊ n/(k+1) ⌋ 版本的
vector<int> majorityElement(vector<int>& nums)
{
int t[3], cnt[3] = { 0 };
int k = 2;
for (int i = 1; i <= k; i++)
t[i] = 1e9 + 1;
bool f;
for (int x : nums)
{
f = true;
for (int i = 1; i <= k; i++)
{
if (x == t[i])
{
cnt[i]++;
f = false;
break;
}
}
if (f)
{
f = true;
for (int i = 1; i <= k; i++)
{
if (cnt[i] == 0)
{
f = false;
t[i] = x;
cnt[i] = 1;
break;
}
}
if (f)
{
for (int& xx : cnt)
{
xx--;
}
}
}
}
vector<int> ans;
memset(cnt, 0, sizeof cnt);
for (int x : nums)
{
for (int i = 1; i <= k; i++)
{
if (x == t[i])
cnt[i]++;
}
}
for (int i = 1; i <= k; i++)
{
if (cnt[i] > nums.size() / (k + 1))
ans.push_back(t[i]);
}
return ans;
}