【LeetCode】第169题——多数元素(难度:简单)
题目描述
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 [ n/2 ] 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
-
示例 1:
输入: [3,2,3]
输出: 3 -
示例 2:
输入: [2,2,1,1,1,2,2]
输出: 2
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/majority-element
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
思路一:HashMap。用key与value记录出现过的数字与出现次数,当某个数字的出现次数大于 [ n/2 ],则返回这个数字。
思路二:Boyer-Moore 投票算法。
详细来说比较难以解释,但…以架空世界中某国大选为例吧(如有雷同,纯属巧合)。
候选人有bd和tp。选bd的人多于半数,因此答案是bd。
那么开始:
先把选举人中第一个人拉过来问一下选的谁,假设是选bd的,那么就推举bd为候选人candidate,count设置为1。然后再遍历下一个人,若选bd则count+1,若选tp则count-1,当count=0时则把下一个投票人选择的作为新的candidate并继续上述操作。
原理:若tp为当前候选人,多数派bd的选举人会阻止其当选,即count=0;若bd为当前候选人,多数派bd的选举人会保证他顺利当选,即count>0。
(不知道大家对该方法有没有稍微的理解,苦笑)
以上是LeetCode评论区大佬对于Boyer-Moore 投票算法解释(稍作魔改),真乃神人!
代码详解
思路一:HashMap
class Solution {
public int majorityElement(int[] nums) {
int target = nums.length / 2; // 目标是大于一半
HashMap<Integer, Integer> hm = new HashMap<>();
for(int i = 0; i < nums.length; ++i) {
if(hm.containsKey(nums[i])) { // 如果key存在就让value+1
int val = hm.get(nums[i]) + 1;
if(val > target) { // 在value+1后便判断该值是否大于总数一半,即可提前终止循环,不用全部遍历完整个数组
return nums[i];
} else {
hm.replace(nums[i], val); // 不大于一半的话就把+1后的值赋给value,并继续遍历
}
} else {
hm.put(nums[i], 1); // 如果key不存在就新添加一个key,并设定value为1
}
}
return nums[0]; // 该返回值还是有点讲究的,详见下方注意点章节
}
}
思路二:Boyer-Moore 投票算法
class Solution {
public int majorityElement(int[] nums) {
int count = 0; // 思路二中的count
int candidate = 0; // 候选人,这里便不只是bd和tp二元对象啦
for(int num : nums) {
if(count == 0) { // 循环开始(或候选人更迭)
candidate = num;
count = 1;
} else {
if(num != candidate) {
--count; // 当前选民选举的不是候选人时count-1
} else {
++count; // 当前选民选举的是候选人时count+1
}
}
}
return candidate;
}
}
注意点
-
HashMap思路里为什么最后返回nums[0]?
因为当nums只有一个元素时,根据循环部分的代码,只会执行一遍添加新的key,并把value置1,然后便退出循环,不会从超过一半便return的那部分代码中跳出循环。所以最后的return nums[0]是为了应对单元素数组时的情况。 -
还有更多思路,只不过思路一是很容易想到的,思路二是逛官方题解时发现最有意思的一个。
-
想对Boyer-Moore 投票算法进行深入了解的话,
请做好看不懂的准备。