每日一题(二分+枚举)

1.题目解析

分组 (nowcoder.com)

主要题意就是,按照不同的序号进行分组,同一序号只能放在同一组,并且要求答案是分成要求的组数且在符合组数的前提下求出最大值最小的一个。

2.思路分析

这个题可以说是一个比较容易误导人的一道题,永远都是想通过人数来推组数,这样复杂度也很高重复计算也很多,这题主要解法是一种反推法:枚举最终的结果,从来推出最多人数组的最小数。

1.统计人数

使用hash表进行统计,声部为键,出现的次数为值

2.枚举最终结果,找出符合m组且最大人数最小的

人数越多,组数越少,所以说枚举范围就是 1 ~ 最多声部的人数

比如枚举到3了,最多声部的人数为8,8就可以分成2个3 一个2,其他的也按照这样分比如 人数2 就是一组,这样会得到组数count 然后和m比较如果是符合的count <= m直接返回即可,因为如果是7也可以随便拆出来一组,因为他不管我们怎么返回,他要最大 人数的那个组的人数。

3.二分进行优化

存在二段性

下面是我手写的分析过程和模拟过程

3.代码实现

1.暴力枚举

java 复制代码
 public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextInt()) { // 注意 while 处理多个 case
            int n = in.nextInt();
            Map<Integer,Integer> hash = new HashMap<>();
            int m = in.nextInt();
            int max = 0;//所有声部的最大值
            for (int i = 0; i < n; i++) {
                int x = in.nextInt();
                hash.put(x,hash.getOrDefault(x,0) + 1);
                max = Math.max(hash.get(x), max);
            }
            //处理边界情况, 类型大于组数就无法分
            int kinds = hash.size();
            if (kinds > m){
                System.out.println(-1);
                continue;
            }
            for (int i = 1; i <= max; i++) {
                //判断最多人数为x的时候是否能分成m组
                int count = 0;//统计能分成组
                for (int value : hash.values()) {
                    count += value / i + (value % i == 0 ? 0 : 1);
                }
                if (count <= m) {
                    System.out.println(i);
                    break;
                }
            }
        }
    }

2.二分进行优化

java 复制代码
public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextInt()) { // 注意 while 处理多个 case
            int n = in.nextInt();
            Map<Integer,Integer> hash = new HashMap<>();
            int m = in.nextInt();
            int max = 0;//所有声部的最大值
            for (int i = 0; i < n; i++) {
                int x = in.nextInt();
                hash.put(x,hash.getOrDefault(x,0) + 1);
                max = Math.max(hash.get(x), max);
            }
            //处理边界情况, 类型大于组数就无法分
            int kinds = hash.size();
            if (kinds > m){
                System.out.println(-1);
                continue;
            }
            int ans = 1; // 记录答案
            int start = 1;
            int end = max;
            while(start <= end){ // 二分查找
                int mid = (start + end) / 2;
                int count = 0;//统计能分成多少组
                for (int value : hash.values()) {
                    count += value / mid + (value % mid == 0 ? 0 : 1);//最少组数
                }
                if (count <= m) {//是答案但不是最符合的往右搜
                    end = mid - 1;
                    ans = mid; // 更新答案
                }else {//不符合要求,组数太多了,往右搜
                    start = mid + 1;
                }
            }
            System.out.println(ans); // 输出答案
        }
    }

4.总结

通过解决这个问题,我深入理解了分组算法的原理和应用。我的解决方案虽然简单,但已经相当有效。在未来,我可以进一步探索和优化分组算法,以解决更复杂的问题,并应用于更广泛的领域。

相关推荐
吞下星星的少年·-·30 分钟前
牛客技能树:一道GCD问题(排序,数论)
算法
m沐沐40 分钟前
【计算机视觉】人脸识别三大经典算法:LBPH、Eigenfaces、FisherFaces 原理与实战
图像处理·人工智能·深度学习·opencv·算法·机器学习·计算机视觉
Lumos1861 小时前
嵌入式常用滤波算法与控制算法(5)卡尔曼滤波(下)
算法
Lumos1861 小时前
嵌入式常用滤波算法与控制算法(6)互补滤波
算法
Tisfy1 小时前
LeetCode 3536.两个数字的最大乘积:O(1)空间维护max2
数学·算法·leetcode·题解
知识分享小能手1 小时前
统计学学习教程,从入门到精通,一元线性回归 —— 知识点详解(17)
学习·算法·线性回归
艾斯特_2 小时前
Function Calling与工具调用:让模型从回答走向执行
人工智能·python·算法·ai
hold?fish:palm2 小时前
11 滑动窗口最大值
数据结构·算法
xvhao20132 小时前
T750414 【游戏】计算24点 题解
数据结构·c++·算法·游戏
手写码匠2 小时前
Android 17 灵魂拷问深度解析:隐私、大屏、AI 端侧全面适配实战
人工智能·深度学习·算法·aigc