摩尔投票
初步认识
涉及题目
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)