题目
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
思路一 暴力
- 使用hash表来记录数组的元素,和出现个数
- k-v,k表示数组的元素,v表示元素出现的个数
- 然后遍历哈希表,找到v最大的那个键值
class Solution {
public int majorityElement(int[] nums) {
Map<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
if (!map.containsKey(num)) {
map.put(num, 1);
} else {
map.put(num, map.get(num) + 1);
}
}
Map.Entry<Integer, Integer> a = null;
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (a == null || entry.getValue() > a.getValue()) { //找到最大值的键值
a = entry;
}
}
return a.getKey();
}
}
- 里面的Map.Entry 原理
- keySet()方法返回值是Map中key值的集合;entrySet()的返回值也是返回一个Set集合,此集合的类型为Map.Entry。
- Map.Entry是Map声明的一个内部接口,此接口为泛型,定义为Entry<K,V>。它表示Map中的一个实体(一个key-value对)。接口中有getKey(),getValue方法。
- 因为Map这个类没有继承Iterable接口所以不能直接通过map.iterator来遍历(list,set就是实现了这个接口,所以可以直接这样遍历),所以就只能先转化为set类型,用entrySet()方法,其中set中的每一个元素值就是map中的一个键值对,也就是Map.Entry<K,V>了,然后就可以遍历了。
复杂度分析
时间复杂度:O (N),遍历数组的每一个元素,加入到hash表中
空间复杂度:O(N),hash表存放空间,最大为N/2,所以为O(N)
思路二 排序
- 对数组元素进行排序
- 然后,数组中间位置,一定为多数元素。因为题目规定多数元素一定大于n/2
class Solution {
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length / 2];
}
复杂度分析
时间复杂度:O(nlogn),就是排序的时间复杂度
空间复杂度:O(logn),或者其他,看排序的算法。
思路三,投票法
- 初始值 为nums[0],次数为1
- 遇到相同的次数加一,遇到不同的次数减一
- 次数为0,换值
- 遍历完数组,当前的值,就是多数元素
为什么
相当于是遇到相同的则 + 1,遇到不同的 - 1。
且“多数元素”的个数> ⌊ n/2 ⌋,其余元素的个数总和<= ⌊ n/2 ⌋。
因此“多数元素”的个数 - 其余元素的个数总和 的结果 肯定 >= 1。
极端情况下,这就相当于每个“多数元素”和其他元素 两两相互抵消,抵消到最后肯定还剩余至少1个“多数元素”。
class Solution {
public int majorityElement(int[] nums) {
int count = 1;
int maj = nums[0];
for (int i = 1; i < nums.length; i++) {
if (maj == nums[i])
count++;
else {
count--;
if (count == 0) {
maj = nums[i + 1]; //抵消了,往下一层走,刚好下一层会相等,count就会等于1
}
}
}
return maj;
}
}
复杂度分析
时间复杂度:O(N),就遍历了数组
空间复杂度:O(1)