题目描述
解题思路
哈希法
public int majorityElement(int[] nums) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
}
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (entry.getValue() > nums.length / 2) return entry.getKey();
}
return 0;
}
排序法
由于一定有众数,且众数占数组长度一半,所以排序之后取中间值。
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length / 2];
}
摩尔投票法
推论一: 若记 众数 的票数为 +1 ,非众数 的票数为 -1 ,则一定有所有数字的 票数和 > 0 。
推论二: 若数组的前 a 个数字的 票数和 =0 ,则 数组剩余 (n-a) 个数字的 票数和一定仍 >0 ,即后 (n-a) 个数字的 众数仍为 x 。
根据以上推论,记数组首个元素为n,众数为α,遍历并统计票数。
当发生票数和=0时,剩余数组的众数一定不变,这是由于:
- 当n1= a :抵消的所有数字,有一半是众数α。
- 当n1≠a :抵消的所有数字,众数α的数量最少为0个,最多为一半。
利用此特性,每轮假设发生票数和=0都可以缩小剩余数组区间。当遍历完成时,最后一轮假设的数字即为众数。
也就是把第一个数字当作备选者,遍历数组,如果相同则选举加一,如果不相同则选举减一,当选举为0的时候,此时就需要重新选择备选者进行投票。
// 投票法
public int majorityElement(int[] nums) {
int x = 0, votes = 0;
for (int num : nums) {
if (votes == 0) x = num;
if (num == x) votes++;
else votes--;
}
// 如果不存在众数,需要遍历x进行验证本题说明了存在众数
/*int count = 0;
for (int num : nums) {
if (x == num) count++;
}
if (count > nums.length / 2) return x;*/
return x;
}
扩展
此时如果大于数组长度一半的众数不一定存在,那么最后一个数就不一定是需要找的众数,所以还需要遍历一次数字,使用计数器技术到底该数是不是需要找的数。
// 投票法
public int majorityElement(int[] nums) {
int x = 0, votes = 0;
for (int num : nums) {
if (votes == 0) x = num;
if (num == x) votes++;
else votes--;
}
// 如果不存在众数,需要遍历x进行验证本题说明了存在众数
int count = 0;
for (int num : nums) {
if (x == num) count++;
}
if (count > nums.length / 2) return x;
return x;
}