【优先队列】为了使得最后的平均通过率最大,我们应该让(pass + 1) / (total + 1) - pass / total大的先用掉extra,所以对于两个班级可以按照这个进行排序,接下来发现extra只有1e5,classes也是1e5,如果用优先队列来存classes的话,操作1e5次也不会超时。
class Solution {
public double maxAverageRatio(int[][] classes, int extraStudents) {
int n = classes.length;
PriorityQueue<double[]> queue = new PriorityQueue<double[]>((a, b) -> {
return (a[0] + 1) / (a[1] + 1) - a[0] / a[1] > (b[0] + 1) / (b[1] + 1) - b[0] / b[1]? -1: 1;
});
for (int[] c: classes) {
queue.offer(new double[] {c[0], c[1]});
}
int ex = extraStudents;
double sum = 0;
while (ex-- > 0) {
double[] t = queue.peek();
queue.poll();
queue.offer(new double[] {t[0] + 1, t[1] + 1});
}
for (double[] c: queue) {
sum += c[0] / c[1];
}
return sum / n;
}
}
【手写堆】试一下用Java写个大根堆
class Solution {
int n;
double[][] heap;
boolean cmp(int i, int j) {
double[] a = heap[i], b = heap[j];
return (a[0] + 1) / (a[1] + 1) - a[0] / a[1] > (b[0] + 1) / (b[1] + 1) - b[0] / b[1] ? true: false;
}
void swap(int i, int j) {
double a = heap[i][0], b = heap[i][1];
heap[i][0] = heap[j][0]; heap[i][1] = heap[j][1];
heap[j][0] = a; heap[j][1] = b;
}
void down(int i) {
int l = i * 2, r = i * 2 + 1, t = i;
if (l <= n && cmp(l, t)) t = l;
if (r <= n && cmp(r, t)) t = r;
if (t != i) {
swap(t, i);
down(t);
}
}
public double maxAverageRatio(int[][] classes, int extraStudents) {
n = classes.length;
heap = new double[n + 1][2];
int ex = extraStudents;
for (int i = 0; i < n; i++) {
heap[i + 1][0] = classes[i][0];
heap[i + 1][1] = classes[i][1];
}
for (int i = n / 2; i >= 1; i--) down(i);
while (ex-- > 0) {
heap[1][0]++;
heap[1][1]++;
down(1);
}
double sum = 0;
for (int i = 1; i <= n; i++) {
sum += heap[i][0] / heap[i][1];
}
return sum / n;
}
}