LeetCode第 169 题:多数元素(C++)_zj-CSDN博客的进阶
哈希表
就不贴代码了,计数就可以了
摩尔投票法
题目并没有保证一定会有一个元素出现次数在n/3以上。
n/k的众数最多只有k-1个,也就是这题结果可能为一个数或者两个数,或者不存在。
可以看这个解释:从柱形图角度超极速理解,为什么摩尔投票法适用于任意多个候选人 - 求众数 II - 力扣(LeetCode)
我们要先找到出现次数最多的两个数,然后检查这两个数是否符合要求。
class Solution {
public:
vector<int> majorityElement(vector<int>& nums) {
vector<int> res;
if(nums.size() == 0) return res;
int cand1 = 0, cand2 = 0;//两个候选
int cnt1 = 0, cnt2 = 0;//计数
for(auto num : nums){
if(num == cand1){// 如果是候选者1,票数++
++cnt1;
continue;
}
if(num == cand2){// 如果是候选者2,票数++
++cnt2;
continue;
}
if(cnt1 == 0){// 既不是cand1也不是cand2,如果cnt1为0,那它就去做cand1
cand1 = num;
++cnt1;
continue;
}
if(cnt2 == 0){// cand1的cnt1不为0但是cand2的cnt2为0,那他就去做cand2
cand2 = num;
++cnt2;
continue;
}
// 如果cand1和cand2的数量都不为0,那就都-1
--cnt1;
--cnt2;
}
cnt1 = cnt2 = 0;
//还需要检查两个候选者的票数是否真的大于n/3
for(const auto &num : nums){
if(num == cand1) ++cnt1;
else if(num == cand2) ++cnt2;//用else if是为了防止初始值的设定刚好是等于某个元素,比如[0,0,0]这种特例
}
if(cnt1 > nums.size()/3) res.push_back(cand1);
if(cnt2 > nums.size()/3) res.push_back(cand2);
return res;
}
};
摩尔投票法(另一个思路)
最多会有两个元素。
之前的题目我们是通过加1,减1计数的,这儿换个思路。
如果元素a的个数大于总个数的1/3,我们每次遍历碰到这个数就+2,碰到的不是这个数就-1,遍历结束之后我们就能找到这个元素a(会有特殊情况,代码里考虑)。
再考虑除去这个元素的数组,如果剩下的元素里面还有一个元素b出现次数符合要求,那么它在出去元素a的数组里的占比肯定大于1//2,那这不就是169题简单版的摩尔投票吗?就再投一次就可以了。
需要注意的是,题目没有保证目标元素一定会出现,所以每次投票完都需要进行检查。
class Solution {
public:
vector<int> majorityElement(vector<int>& nums) {
vector<int> res;
int num1, cnt = 0;
for(const auto &num : nums){
if(cnt == 0) num1 = num;
cnt += num1 == num ? 2 : -1;
}
cnt = 0;
for(const auto &num : nums){
if(num == num1) ++cnt;
}
if(cnt > nums.size()/3) res.push_back(num1);
//else return res;//这儿不能直接return,因为[6,5,5]这种目标数字在最后一位的,可能会找不到
//考虑出去num1之后的数组
int num2;
cnt = 0;
for(const auto &num : nums){
if(num == num1) continue;
if(cnt == 0) num2 = num;
cnt += num2 == num ? 1 : -1;
}
cnt = 0;
for(const auto &num : nums){
if(num == num2) ++cnt;
}
if(cnt > nums.size()/3) res.push_back(num2);
return res;
}
};