本文已参与「新人创作礼」活动,一起开启掘金创作之路。
摩尔投票
初步认识
涉及题目
LeetCode 169 - Majority Element
算法概述
在给定的数组中,找出其中出现次数超过n/2的元素。题目假定一定存在一个元素出现超过n/2次。
思路
每次删除数组中两个不相同的元素,遍历完数组后,剩下的元素一定是出现超过n/2次的元素。
- 定义候选者
cand赋任意值、计数器count初始化为0 - 遍历数组
- 如果
count值为0,将cand赋值为当前值nums[i],count赋值为1 - 如果
count值不为0,且当前值nums[i]等于cand的值,则count加一,否则count减一
- 如果
- 遍历完成后,
cand即为所求元素
count减一可以理解为在数组中删掉了当前元素nums[i]和一个cand的元素,当count元素为0时可以理解为前面的所有数都已经相互抵消。
代码实现
public int majorityElement(int[] nums) {
int cand = 0;
int count = 0;
for (int i = 0; i< nums.length; ++i) {
if (count == 0) {
count = 1;
cand = nums[i];
continue;
}
if (cand == nums[i]) count++;
else count--;
}
return cand;
}
进阶
涉及题目
LeetCode 229 - Majority Element II
思路
题目要找出出现次数大于n/3的元素,但并不保证元素一定存在。
每次删除三个不同元素,最后留下的(最多两个)一定是出现次数最多的,但不一定大于n/3次,还需要再遍历一次数组计数是否大于n/3。由此可推出超过n/k的元素(最多k-1个)。
- 定义候选者
cand1和cand2赋任意值、计数器count1和count2初始化为0 - 遍历数组第一次找出可能的元素
- 如果当前值
nums[i]等于cand1或cand2的值,则对应的count1或count2加一 - 如果
count1或count2值为0,将cand1或cand2赋值为当前值nums[i],对应count赋值1 - 否则
count1和count2均减一
- 如果当前值
count1和count2赋值为0- 遍历数组第二次判断是否满足条件(出现次数大于
n/3)- 判断
nums[i]是否与cand1或cand2相等,相等则对应count加一
- 判断
- 最终大于
n/3次数的元素即为所求
代码实现
public List<Integer> majorityElement(int[] nums) {
List<Integer> result = new ArrayList<>();
if (nums.length == 0) return result;
int cand1 = 0;
int cand2 = 0;
int count1 = 0;
int count2 = 0;
for (int i = 0; i < nums.length; ++i) {
if (cand1 == nums[i]) {
count1++;
continue;
}
if (cand2 == nums[i]) {
count2++;
continue;
}
if (count1 == 0) {
count1 = 1;
cand1 = nums[i];
continue;
}
if (count2 == 0) {
count2 = 1;
cand2 = nums[i];
continue;
}
count1--;
count2--;
}
count1 = 0;
count2 = 0;
for (int i = 0; i < nums.length; ++i) {
if (cand1 == nums[i]) count1++;
else if (cand2 == nums[i]) count2++;
//一定要else if,因为cand1和cand2可能是相同元素
}
if (count1 > (nums.length)/3) result.add(cand1);
if (count2 > (nums.length)/3) result.add(cand2);
return result;
}
参考资料
摩尔投票算法( Boyer-Moore Voting Algorithm)