题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2
限制:
1 <= 数组长度 <= 50000
考点:
leet大佬的思路
- 哈希表统计法: 遍历数组 nums ,用 HashMap 统计各数字的数量,最终超过数组长度一半的数字则为众数。此方法时间和空间复杂度均为 O(N)。
- 数组排序法: 将数组 nums 排序,由于众数的数量超过数组长度一半,因此数组中点的元素 一定为众数。此方法时间复杂度 O(N log_2 N)。
- 摩尔投票法: 核心理念为 “正负抵消” ;时间和空间复杂度分别为 O(N) 和 O(1);是本题的最佳解法。
摩尔投票法思想:用target记录上一次访问的值,count表明当前值出现的次数,如果下一个值和当前值相同那么count++;如果不同count–,减到0的时候就要更换新的target值了,因为如果存在超过数组长度一半的值,那么最后target一定会是该值。可以这样理解,count的自加和自减就是在描述一种抵消关系,由于超过一半的出现次数,导致最后的target一定会是该值。
我的思路:哈希集合
哈希HashMap的方法在这里
解决方法
一、哈希
class Solution {
public int majorityElement(int[] nums) {
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for(int i=0; i<nums.length; i++){
if(map.containsKey(nums[i])){
map.put(nums[i], map.get(nums[i])+1);
}else{
map.put(nums[i], 1);
}
int len = nums.length/2;
//i>=len,带等号,是为了满足长度为1的情况,i是从0开始的
//第二个条件,出现次数超过一半
if(i >= len && map.get(nums[i]) > len)
return nums[i];
}
return 0; //不存在满足要求的数字或数组长度为0
}
}
二、调用API
class Solution {
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length/2];
}
}
三、摩尔投票法
class Solution {
public int majorityElement(int[] nums) {
int count = 1, target = nums[0];
for(int i=1; i<nums.length; i++){
if(target == nums[i]){
count++;
}else{
count--;
}
if(count == 0){
target = nums[i];
count = 1;
}
}
return target;
}
}