华为OD机试真题-查找众数及中位数-java代码

原题链接

华为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

也可以完全把最后众数的数组构建出来,就是浪费点空间,不用推导下标的映射关系,而且省头发.

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值