1、题目描述
【JZ28】数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
知识点:数组,排序,哈希
难度:☆
2、解题思路
本题其实是找众数,也就是出现次数最多的那个数,然后判断这个众数出现的次数是否占了元素总个数的一半。
2.1 哈希法
遍历数组,把每一种数字和它所出现的次数都保存在一个HashMap<Integer, Integer>
中。
遍历HashMap
,找出众数num
;
判断num>(length/2)
是否满足,是则返回num
,否则返回0。
2.2 排序法
先把数组进行从小到大排序,然后判断正中间的那个数字出现了多少次,如果它出现的次数大于总个数的一半,那就是我们要找的,否则不存在我们要找的数。
3、解题代码
3.1 哈希法
package pers.klb.jzoffer.medium;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
/**
* @program: JzOffer2021
* @description: 数组中出现次数超过一半的数字(哈希法)
* @author: Meumax
* @create: 2020-07-08 16:32
**/
public class MoreThanHalfNum {
public int MoreThanHalfNum_Solution(int[] array) {
int length = array.length;
if (length == 0) {
return 0;
}
HashMap<Integer, Integer> map = new HashMap<>();
// 记录每一个元素出现的次数
for (int num : array) {
if (map.containsKey(num)) {
map.put(num, map.get(num) + 1);
} else {
map.put(num, 1);
}
}
// 找出出现次数最大的num
Set<Integer> set = map.keySet();
Iterator<Integer> iterator = set.iterator();
Integer num;
Integer value;
while (iterator.hasNext()) {
num = iterator.next();
value = map.get(num);
if (value > (length / 2)) {
return num;
}
}
return 0;
}
}
时间复杂度:O(N)
空间复杂度:O(N)
3.2 排序法
package pers.klb.jzoffer.medium;
import java.util.Arrays;
/**
* @program: JzOffer2021
* @description: 数组中出现次数超过一半的数字(排序法)
* @author: Meumax
* @create: 2020-07-08 16:32
**/
public class MoreThanHalfNum {
public int MoreThanHalfNum_Solution(int[] array) {
int length = array.length;
if (length == 0) {
return 0;
}
Arrays.sort(array); // 从小到大排序
int midNum = array[length / 2];
int count = 0; // 中间数出现的次数
for (int num : array) {
if (num == midNum) {
count++;
}
}
// 可能的众数肯定在数组中间位置
if (count > length / 2) {
return midNum;
}
return 0;
}
}
时间复杂度:取决于排序算法
空间复杂度:取决于排序算法
4、解题心得
本题难度较低,大家都能想到用哈希的方法找出众数。
排序法的复杂度取决于排序算法,数字规模不同的时候不好确定复杂度,因为不同规模的最好排序算法是不一样的。