1792. 最大平均通过率

目录

最大化班级平均通过率 —— 贪心 + 堆优化方案详解

题目描述

输入输出示例

示例 1:

示例 2:

解题分析

核心难点

通过率增益计算

贪心策略

数据结构选择

解题代码

复杂度分析

思路对比和优化讨论

结论


最大化班级平均通过率 —— 贪心 + 堆优化方案详解


题目描述

学校有若干班级,每个班级有若干学生,并且每个班级已有一定数量的学生通过期末考试。现在给你一个二维数组 classes,其中 classes[i] = [pass_i, total_i] 表示第 i 个班级中共有 total_i个学生,其中只有 pass_i个学生能通过考试。

此外,你还有 extraStudents 个聪明学生,这些学生 一定能通过任何班级的考试。你的任务是把这 extraStudents 个学生分配到各个班级中,使得所有班级的平均通过率最大。

  • 通过率:班级中通过考试学生数除以该班级总人数
  • 平均通过率:所有班级的通过率之和除以班级数目

目标: 返回分配完所有额外学生后的最大平均通过率。结果允许与标准答案误差在 10^-5 以内。


输入输出示例

示例 1:

输入:
classes = [[1,2],[3,5],[2,2]]
extraStudents = 2

输出:
0.78333

解释:
将两个额外的学生都分配到第一个班级,班级状态变为:
第一个班级:pass=3, total=4, 通过率=3/4=0.75
第二个班级:通过率=3/5=0.6
第三个班级:通过率=2/2=1.0

平均通过率 = (0.75 + 0.6 + 1.0) / 3 = 0.78333

示例 2:

输入:
classes = [[2,4],[3,9],[4,5],[2,10]]
extraStudents = 4

输出:
0.53485

解题分析

核心难点

  • 额外学生可以自由分配,但要让平均通过率最大化。
  • 如何判断“给哪个班级分配额外学生,能带来最大增益”?

通过率增益计算

一个班级的当前通过率是:

r = \frac{pass}{total}

给班级分配一个额外的聪明学生后,通过率变为:

r' = \frac{pass + 1}{total + 1}

增益(gain)是:

gain = r' - r = \frac{pass + 1}{total + 1} - \frac{pass}{total}

显然,我们每次都应该选择增益最大的班级,优先把额外学生分配给它。


贪心策略

  • 计算每个班级增加一个学生的增益。
  • 选择增益最大的班级分配一个额外学生。
  • 更新该班级的 passtotal
  • 重新计算该班级的新增益。
  • 重复上述过程,直到分配完所有额外学生。

数据结构选择

  • 使用最大堆(优先队列)存储班级的增益和当前状态。
  • Python 自带的 heapq最小堆,因此存储负的增益值来模拟最大堆。

解题代码

import heapq
from typing import List

class Solution:
    def maxAverageRatio(self, classes: List[List[int]], extraStudents: int) -> float:
        def gain(pass_, total):
            # 计算分配一个额外学生后带来的增益
            return (pass_ + 1) / (total + 1) - pass_ / total
        
        # 建立最大堆,存储(-增益, pass, total)
        heap = []
        for pass_, total in classes:
            g = gain(pass_, total)
            heapq.heappush(heap, (-g, pass_, total))
        
        # 分配额外学生
        for _ in range(extraStudents):
            g, pass_, total = heapq.heappop(heap)
            pass_ += 1
            total += 1
            new_g = gain(pass_, total)
            heapq.heappush(heap, (-new_g, pass_, total))
        
        # 计算最终平均通过率
        total_classes = len(classes)
        result = 0
        while heap:
            _, pass_, total = heapq.heappop(heap)
            result += pass_ / total
        
        return result / total_classes

复杂度分析

  • 假设班级数为 n,额外学生数为 m
  • 每次分配学生,我们执行一次堆操作(弹出+插入),时间复杂度为 O(log n)
  • 总共分配 m 个学生,时间复杂度为 O(m log n)
  • 空间复杂度为 O(n),存储堆。

思路对比和优化讨论

  • 暴力尝试每个分配方案明显不可行,组合爆炸,效率极低。
  • 贪心策略是基于“每次选最大增益”局部最优选择,整体最优得到保证。
  • 使用堆保证每次获取最大增益的班级是高效的。
  • 对于非常大规模数据,也可以考虑用数学方法或并行化,但当前方案已是最佳实用解。

结论

通过贪心和堆的巧妙结合,我们可以高效地将额外的聪明学生分配给那些增益最大的班级,从而最大化所有班级的平均通过率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值