每日一题——最大平均通过率

85 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 19 天,点击查看活动详情


1792. 最大平均通过率

一所学校里有一些班级,每个班级里有一些学生,现在每个班都会进行一场期末考试。给你一个二维数组 classes ,其中 classes[i] = [passi, totali] ,表示你提前知道了第 i 个班级总共有 totali 个学生,其中只有 passi 个学生可以通过考试。

给你一个整数 extraStudents ,表示额外有 extraStudents 个聪明的学生,他们 一定 能通过任何班级的期末考。你需要给这 extraStudents 个学生每人都安排一个班级,使得 所有 班级的 平均 通过率 最大 。

一个班级的 通过率 等于这个班级通过考试的学生人数除以这个班级的总人数。平均通过率 是所有班级的通过率之和除以班级数目。

请你返回在安排这 extraStudents 个学生去对应班级后的 最大 平均通过率。与标准答案误差范围在 10-5 以内的结果都会视为正确结果。

 

示例 1:

输入: classes = [[1,2],[3,5],[2,2]], extraStudents = 2
输出: 0.78333
解释: 你可以将额外的两个学生都安排到第一个班级,平均通过率为 (3/4 + 3/5 + 2/2) / 3 = 0.78333

 

提示:

  • 1 <= classes.length <= 105
  • classes[i].length == 2
  • 1 <= passi <= totali <= 105
  • 1 <= extraStudents <= 105

思路

要想提高整体的平均通过率,我们需要将通过率低的班级的通过率提高,但这里有一个坑,我们要提高的不一定是通过率最低的班级,我们要看提高哪个班级的通过率获得的收益最大,即比较增加聪明学生后的通过率和原通过率的差值来决定我们是否将聪明的学生安排在该班级。

我们可以通过小根堆来实现计算所有班级通过率对增长差值,每次安排聪明的学生时,可以将通过率增加的差值最大的出堆,然后增加后再将该班级入堆重新计算通过率增加差值。

最后,将堆中所有的班级取出,计算平均通过率得到最终答案。

题解

class Solution {
    public double maxAverageRatio(int[][] classes, int extraStudents) {
        int n = classes.length;
        PriorityQueue<int[]> heap = new PriorityQueue<>(new Comparator<int[]>() {
            public int compare(int[] o1, int[] o2) {
                double d1 = 1.0 * (o1[0] + 1) / (o1[1] + 1) - 1.0 * o1[0] / o1[1];
                double d2 = 1.0 * (o2[0] + 1) / (o2[1] + 1) - 1.0 * o2[0] / o2[1];
                return d1 >= d2? -1: 1;
            }
        });
        for(int i = 0; i < n; i++) {
            heap.offer(classes[i]);
        }
        for(int i = 0; i < extraStudents; i++) {
            int[] tmp = heap.poll();
            heap.offer(new int[]{tmp[0] + 1, tmp[1] + 1});
        }
        double sum = 0;
        while(!heap.isEmpty()) {
            int[] tmp = heap.poll();
            sum += 1.0 * tmp[0] / tmp[1];
        }
        return sum / n;
    }
}

如果你有其他的思路或者更好的解法,亦或者你发现了文章出现了错误或有不足,欢迎在评论区和我交流,我看到了一定会回复。

写文章不易,如果你觉得文章对你有帮助,麻烦点一下点赞、收藏,你的支持是我写文章的最大动力!