原题链接
华为OD机试真题-查找众数及中位数-2024年OD统一考试(C卷)-CSDN博客
思路
使用map结构,k是数组中的值,v统计出现的次数.
在统计各个值出现的频率的同时,记录当前出现的最大频次maxTimes 与辅助数组的长度size.
辅助数组helpArr记录每一个众数,且只记录一次,如,1 1 1 2 2 2 3 3 3中,数组只存 1 2 3,且升序排列
辅助数组中,所有的众数出现的次数一样都是maxTimes.总共有total = size * maxTimes个众数.
total 是偶数的情况
从1开始的序列中,第index1 = total / 2 和index2 = total / 2 + 1 个数的和的一半是他的中位数.
那么,映射到从0开始的辅助数组helpArr中,下标为
index1 / maxTimes + (index1 % maxTimes == 0 ? 0 : 1) - 1
与
index2 / maxTimes + (index2 % maxTimes == 0 ? 0 : 1) - 1
和的一半是他的中位数.
total是奇数的情况
第index1 = total / 2 + 1个数是他的中位数
映射到辅助数组中,下标为
index1 / maxTimes + (index1 % maxTimes == 0 ? 0 : 1) - 1
是他的中位数
java代码
实现代码
private static void solution(int[] arr) {
//k是数组中的值,v是出现次数
HashMap<Integer, Integer> map = new HashMap<>();
//默认最大词频
int maxTimes = 1;
//新数组的长度,我没有构建出完整的数组,这个数组是由众数组成的,但在这个数组中每个众数只出现一次
int size = 0;
//统计数出现的频率
for (int i = 0; i < arr.length; i++) {
if (map.containsKey(arr[i])) {
Integer times = map.get(arr[i]) + 1;
map.put(arr[i], times);
//如果最大值和当前值相等,意味着又出现了一个众数
if (maxTimes == times) {
size++;
}
//如果最大值小于当前词频,意味着存放众数的数组长度变为1
if (maxTimes < times) {
size = 1;
}
maxTimes = Math.max(maxTimes, times);
} else {
map.put(arr[i], 1);
}
}
size = size == 0 ?arr.length : size;
//创建前面提到的数组
Integer[] helpArr = new Integer[size];
int index = 0;
//统计所有众数的次数
//int total = 0;
int total = size * maxTimes;
for (Integer item : map.keySet()) {
if (map.get(item).equals(maxTimes)) {
helpArr[index++] = item;
//统计所有众数的次数,因为每次相加的值都一样,而且知道相加了几次,所以直接计算了 total = size * maxTimes;
//total += map.get(item);
}
}
//升序排序
Arrays.sort(helpArr);
int temp = 0;
//偶数长度,选择两个值
if (total % 2 == 0) {
//index1 和index2 表示,在从1开始的序列中,他们的中位数是第index1和index2个数
int index1 = total / 2;
int index2 = index1 + 1;
//helpArr里所有的众数出现的频率都一样,都是maxTimes,
// index1 / maxTimes + (index1 % maxTimes == 0 ? 0 : 1),用来确定是index1是在第几个众数的范围内
// 上述值减去1 是在数组中的位置
int value1 = helpArr[index1 / maxTimes + (index1 % maxTimes == 0 ? 0 : 1) - 1];
int value2 = helpArr[index2 / maxTimes + (index2 % maxTimes == 0 ? 0 : 1) - 1];
int result = value1 + ((value2 - value1) >> 1);
System.out.println(result);
} else {
//奇数长度 1 2 3 4 5
int index1 = total / 2 + 1;
int result = helpArr[index1 / maxTimes + (index1 % maxTimes == 0 ? 0 : 1) - 1];
System.out.println(result);
}
}
主函数
public static void main(String[] args) {
solution(new int[]{2, 1, 5, 4, 3, 3, 9, 2, 7, 4, 6, 2, 15, 4, 2, 4});
solution(new int[]{10, 11, 21, 19, 21, 17, 21, 16, 21, 18, 15});
solution(new int[]{5, 1, 5, 3, 5, 2, 5, 5, 7, 6, 7, 3, 7, 11, 7, 55, 7, 9, 98, 9, 17, 9, 15, 9, 9, 1, 39});
}
测试结果
3
21
7
ps
也可以完全把最后众数的数组构建出来,就是浪费点空间,不用推导下标的映射关系,而且省头发.