目录
数组中出现次数超过一半的数字
描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1
输入
[1, 2, 3, 2, 2, 2, 5, 4, 2]
输出
2
限制
1 <= 数组长度 <= 50000
方法一:哈希表统计法
我们用哈希表的键值不可重复来计数,当计数达到数组长度一半时返回当前元素。
class Solution {
public int majorityElement(int[] nums) {
if (nums.length==1) return nums[0];
int target=nums.length/2;
HashMap<Integer,Integer> map=new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (!map.containsKey(nums[i])){//如果表中没有这个元素
map.put(nums[i],1);//添加元素,个数为1
}else{//如果表中已经有这个元素了,那么个数加1即可
int times = map.get(nums[i]);
if (times+1>target){
return nums[i];//如果出现次数超过长度一半了,直接返回当前元素
}
map.put(nums[i],times+1);//个数加1
}
}
return 0;
}
}
方法二:数组排序法
当我们对数组进行排序,众数一定会在数组的中点处,否则不满足出现次数大于数组长度的一半。
很长时间没写排序算法了,写个快排练练手。
class Solution {
public int majorityElement(int[] nums) {
int arr[]=QuickSort(nums,0,nums.length-1);
return arr[arr.length/2];
}
public int[] QuickSort(int[] arr, int low, int high){
if (low<high){
int curPos=Partition(arr,low,high);//找到第一个元素在数组中的位置
QuickSort(arr,low,curPos-1);//递归对元素左边进行排序
QuickSort(arr,curPos+1,high);//递归对元素右边进行排序
}
return arr;
}
public static int Partition(int[] arr, int low, int high){
int curPos=low;
int curVal=arr[low];
for (int i = low+1; i <= high; i++) {
if (arr[i]<curVal){
curPos++;
if (curPos!=i){
swap(arr,i,curPos);
}
}
}
arr[low]=arr[curPos];
arr[curPos]=curVal;
return curPos;
}
public static void swap(int[] arr, int a, int b){
int temp=arr[a];
arr[a]=arr[b];
arr[b]=temp;
}
}
排序的方法就是时间太慢了。
方法三:摩尔排序法
本方法是最巧妙的,也是本题的最优解。
我们假设数组nums的众数为x,并且数组长度为n,此时如果我们给众数的票数记为+1,非众数的票数记为-1,那么所有数字的票数和一定大于0。
如果数组的前a个数字票数和为0,那么数组剩余n-a个数字的票数和一定仍然大于0,即后面n-a个数字的众数仍然为x。
我们假设第一个数x0为众数,那么开始对票数进行累加,当票数和为0时我们就可以不看前面的数组,这里有两种情况:
- 第一个数x0确实为众数,将前面票数和为0的部分去掉之后,后面的数组众数仍然为x0
- 第一个数x0不是众数,那么去除前面的部分之后,后面的数组众数仍然不改变,只不过不是x0罢了
这样我们可以一直缩减数组的空间,直到最后假设某个数xn为众数遍历完成后票数和为正,那么此时的xn就是我们要找的真正的众数。
class Solution {
public int majorityElement(int[] nums) {
if (nums.length==1) return nums[0];
int sum=1;
int target=nums[0];
for (int i = 1; i < nums.length; i++) {
if (sum==0){//如果此时票数和为0,则更新众数为当前元素
target=nums[i];
}
if (nums[i]==target){//如果为众数,票数+1
sum+=1;
}else{//如果为非众数,票数-1
sum-=1;
}
}
return target;
}
}