前言
优先队列的本质是,一个堆 + FIFO的队列,即一个可以有序出队的队列。而使用优先队列最关键的点就是堆的比较规则。
一、最大平均通过率
二、优先队列
// 贪心,将聪明人放入可提升最高的班级,这个班级的通过率提升最高,平均通过率就更高。
// 优先队列存班级pass和total,以通过率作为比较指标,形成大顶堆。
class Solution {
public double maxAverageRatio(int[][] classes, int extraStudents) {
PriorityQueue<int[]> pq = new PriorityQueue<>((p,q)->{
double a = (q[0] + 1) * 1.0 / (q[1] + 1) - q[0] * 1.0 / q[1];
double b = (p[0] + 1) * 1.0 / (p[1] + 1) - p[0] * 1.0 / p[1];
return a > b ? 1 : -1;// 只能返回整数,不能return a - b
});
// 将元素按规则进入大顶堆
for(int[] c : classes) pq.offer(c);
// 加入必过学生
while(extraStudents-- > 0){
int[] c = pq.poll();
c[0]++;
c[1]++;
pq.offer(c);
}
// 统计平均通过率
double pass = 0;
while(!pq.isEmpty()){
int[] c = pq.poll();
pass += c[0] * 1.0 / c[1];
}
return pass / classes.length;
}
}
总结
1)优先队列非常好用,但是从问题到优先队列,以及优先队列的比较规则定义,是非常考验思考能力的。
2)优先队列是有比较规则的,这就和贪心的最优选择有点相关性,注意两者的联系。
参考文献
[1] LeetCode 最大平均通过率