问题描述
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
题目来源(https://leetcode-cn.com/problems/majority-element)
示例
输入:[3,2,3]
输出:3
输入:[2,2,1,1,1,2,2]
输出:2
解决思路
分治法
- 问题要求出一个数组中出现次数超过本数组的一半元素的数量的元素,我们不妨把它称之为主元素。
- 根据分治的思想,先求出左右两边的主元素。如果左右两边的主元素相等,那么合并之后的主元素仍然是该主元素。
- 左右两边主元素不同的话,那么遍历左右两个数组,统计一下这两个主元素谁出现的次数更多,谁就是合并后数组的主元素。(可以证明主元素必定是左右两个部分主元素的其中一个,反证法假设主元素既不是左边又不是右边的主元素,那么主元素在左边出现的次数小于左边元素个数的一半,右边同理,加起来就少于总元素个数的一半,那么就违背了主元素的定义)。
同归于尽法(应该是叫投票法)
- 主元素的数量既然超过了总元素数量的一半,那么每个主元素和一个普通元素同归于尽,最后数组中最后肯定会剩下一些主元素。
- 因此,我们不妨假设第一个元素为主元素,设置一个count = 1,用以记录主元素的数量,接着遍历整个数组。如果下一个元素和它相等,count++,count变为2。
- 继续遍历,如果下一个元素和它不相同,那就极限一换一,count–,count变为1了。
- 再往下走,下一个元素还是不同,count–,变为0了,换掉了之后主元素也没了,那就令下下一个元素也就是被主元素换掉的那个元素之后的那个元素作为主元素,count从新计为1。
- 按这种同归于尽法。主元素比所有元素的一半还多,换完了所有非主元素,最后还会活下来count个主元素。
java代码
分治法
class Solution {
public static int solve(int left, int right, int [] nums){
if(left == right){
return nums[left];
}
int mid = (left + right) / 2;
int left_most = solve(left, mid, nums);
int right_most = solve(mid + 1, right, nums);
if(left_most == right_most){
return left_most;
}
int count_left = 0, count_right = 0;
for(int i = left; i <= right; i++){
if(nums[i] == left_most){
count_left++;
}
else if(nums[i] == right_most) {
count_right++;
}
}
return count_left > count_right ? left_most : right_most;
}
public int majorityElement(int[] nums) {
int left = 0, right = nums.length - 1;
return solve(left, right, nums);
}
}
同归于尽法
class Solution {
public int majorityElement(int[] nums) {
int key = nums[0], cur = 1, count = 1;
while(cur != nums.length) {
if(nums[cur] == key){ // 自己人就抱团
count++;
cur++;
}
else{ // 不是自己人
count = count - 1; // 先和它同归于尽
if(count == 0){ // 如果兄弟们死光了,下一个元素作为主元素。
cur++;
key = nums[cur];
count = count + 1;
}
cur++;
}
}
return key;
}
}