题目描述:
给定一个大小为 n 的整数数组,找出其中所有出现超过 ⌊ n/3 ⌋
次的元素
方法一:
class Solution {
public:
vector<int> majorityElement(vector<int>& nums) {
int n = nums.size();
vector<int> ans;
int candidate1 = 0; //候选者1
int candidate2 = 0; //候选者2
int vote1 = 0; //候选者1的票数
int vote2 = 0; //候选者2的票数
for (int i = 0; i < n; i++)
{
//如果nums[i]是第一名候选者,其票数加一
if (candidate1 == nums[i]) vote1++;
//如果nums[i]是第二名候选者,其票数加一
else if (candidate2 == nums[i]) vote2++;
//如果原先的candidate1已经没票了,那么将nums[i]作为下一个候选者1
else if (vote1 == 0)
{
candidate1 = nums[i];
vote1++;
}
//如果原先的candidate2已经没票了,那么将nums[i]作为下一个候选者2
else if (vote2 == 0)
{
candidate2 = nums[i];
vote2++;
}
//否则,说明出现了三个不同的数字,相互抵消掉
else
{
vote1--;
vote2--;
}
}
//接着统计candidate1和candidate2在数组中出现的次数
int count1 = 0;
int count2 = 0;
for (int i = 0; i < n; i++)
{
if (nums[i] == candidate1)
{
count1++;
}
else if (nums[i] == candidate2)
{
count2++;
}
}
if (vote1 > 0 && count1 > n / 3) ans.push_back(candidate1);
if (vote2 > 0 && count2 > n / 3) ans.push_back(candidate2);
return ans;
}
};
暑假的时候曾做过【求众数】的第一道题,当时学习了题解所用的摩尔投票法,没想到这一方法还能够拓展到n / k的情况上去。
原本求众数时,即求数组中出现次数大于n / 2的数字,那么假设这个数字为X,可以将数组分为m个X一组,(n - m) 个其他数字一组,由于k > (n - m),所以若是将两两不同的数字相抵消,那么最终剩下的数字一定是X。
同理,若求数组中出现次数大于n / k的数字,那么只要每次将k个不同的数字相抵消,那么最终剩下的那些数字一定是出现次数大于n / k的那些数字。
于是这道题设有两个候选者,每遍历到一个数字,就考虑进行投票或者更换候选者或者抵消3个不同的数字。
注意第一次遍历完之后,还要再求一遍得到的候选者在数组中出现的次数是否大于n / 3,因为考虑一种特殊情况:数组只存在两种数字,那么由于不存在三个数字,所以没有抵消的情况出现,这时候是不能直接判断那种数字的出现次数大于n / 3的。