LeetCode每日一题,2025-09-01
计算大型浮点数相除的时候不要通分,会导致浮点数误差
最大平均通过率
原始想法是把增益公式通分:
x+1y+1−xy通分后y−xy2+y=y−xy(y+1)\frac{x+1}{y+1} - \frac{x}{y} \quad \text{通分后} \quad \frac{y - x}{y^2 + y} = \frac{y-x}{y(y+1)} y+1x+1−yx通分后y2+yy−x=y(y+1)y−x
但是在 Java 中可能出错,因为:
- y2+yy^2 + yy2+y 非常大,而 y−xy - xy−x 相对较小,做浮点数除法可能产生精度误差;
- 浮点数精度误差累积会导致答案不准确。
所以推荐直接使用原公式:
增益=x+1y+1−xy\boxed{\text{增益} = \frac{x+1}{y+1} - \frac{x}{y}} 增益=y+1x+1−yx
这个公式在浮点运算中更稳定,不会因为通分导致精度丢失。
class Node implements Comparable<Node> {double k, x, y;public Node(double k, double x, double y) {this.k = k;this.x = x;this.y = y;}// 定义比较规则:按照 k 降序(大根堆)@Overridepublic int compareTo(Node other) {return Double.compare(other.k, this.k); // k 降序}}public double maxAverageRatio(int[][] classes, int extraStudents) {PriorityQueue<Node> maxHeap = new PriorityQueue<>();for (int[] classInfo : classes) {double k = (classInfo[0] + 1) /(double) (classInfo[1] + 1 ) - (classInfo[0] / (double) classInfo[1]);maxHeap.offer(new Node(k, classInfo[0], classInfo[1]));}while (extraStudents-- > 0 && !maxHeap.isEmpty()) {var cur = maxHeap.poll();cur.x += 1;cur.y += 1;cur.k = (cur.x + 1) / (cur.y + 1) - cur.x / cur.y;maxHeap.offer(cur);// System.out.println(cur.k + " " + cur.x + " " + cur.y);}double ans = 0;while (!maxHeap.isEmpty()) {var cur = maxHeap.poll();ans += cur.x / cur.y;}return ans / classes.length;}