最大平均通过率
难度:
标签:
题目描述
代码结果
运行时间: 1059 ms, 内存: 51.5 MB
/*
题目思路:
1. 使用Java Stream处理数据,计算每个班级的初始通过率。
2. 使用PriorityQueue存储通过率增量并进行排序。
3. 通过流操作分配额外学生并计算最大平均通过率。
*/
import java.util.*;
import java.util.stream.*;
public class MaxAveragePassRateStream {
public double maxAverageRatio(int[][] classes, int extraStudents) {
PriorityQueue<double[]> maxHeap = new PriorityQueue<>((a, b) -> Double.compare(b[0], a[0]));
// 初始增量计算
Arrays.stream(classes).forEach(cls -> {
int pass = cls[0];
int total = cls[1];
double increment = (double)(pass + 1) / (total + 1) - (double)pass / total;
maxHeap.offer(new double[]{increment, pass, total});
});
// 分配额外学生
IntStream.range(0, extraStudents).forEach(i -> {
double[] top = maxHeap.poll();
int pass = (int) top[1];
int total = (int) top[2];
pass++;
total++;
double increment = (double)(pass + 1) / (total + 1) - (double)pass / total;
maxHeap.offer(new double[]{increment, pass, total});
});
// 计算最终平均通过率
return maxHeap.stream().mapToDouble(cls -> cls[1] / cls[2]).average().orElse(0.0);
}
}
解释
方法:
这道题目使用贪心算法和优先队列(堆)来解决。首先,我们计算每个班级添加一个额外学生后的通过率增加量,即(a / b - (a + 1) / (b + 1)),其中a是通过的学生数,b是班级总人数。我们将这个增加量、通过的学生数和总人数作为一个元组放入一个最小堆中。然后,我们逐个将额外的学生分配给能使通过率增加量最大的班级,即每次从堆中弹出增加量最大的元组,更新该班级的通过人数和总人数,重新计算增加量,然后将更新后的元组再次推入堆中。重复这个过程,直到所有额外的学生都被分配完。最后,我们计算所有班级的平均通过率并返回。
时间复杂度:
O(n + k log n)
空间复杂度:
O(n)
代码细节讲解
🦆
为什么选择使用优先队列(堆)来管理班级的通过率增加量,而不是其他数据结构如数组或链表?
▷🦆
在计算通过率增加量时,为什么将增加量定义为`a / b - (a + 1) / (b + 1)`,这种定义能准确反映添加学生后的变化吗?
▷🦆
在题解中提到的`最小堆`实际上应该是最大堆吧,因为需要优先处理增加量最大的班级,这里是不是有误?
▷🦆
如果在分配完所有额外学生后,某些班级的通过率实际上减少了怎么办?这种情况在当前算法中有考虑吗?
▷