Leetcode每日一练--16

一所学校里有一些班级,每个班级里有一些学生,现在每个班都会进行一场期末考试。给你一个二维数组 classes ,其中 classes[i] = [passi, totali] ,表示你提前知道了第 i 个班级总共有 totali 个学生,其中只有 passi 个学生可以通过考试。

给你一个整数 extraStudents ,表示额外有 extraStudents 个聪明的学生,他们 一定 能通过任何班级的期末考。你需要给这 extraStudents 个学生每人都安排一个班级,使得 所有 班级的 平均 通过率 最大 。

一个班级的 通过率 等于这个班级通过考试的学生人数除以这个班级的总人数。平均通过率 是所有班级的通过率之和除以班级数目。

请你返回在安排这 extraStudents 个学生去对应班级后的 最大 平均通过率。与标准答案误差范围在 10-5 以内的结果都会视为正确结果。

示例 1:

输入:classes = [[1,2],[3,5],[2,2]], extraStudents = 2
输出:0.78333
解释:你可以将额外的两个学生都安排到第一个班级,平均通过率为 (3/4 + 3/5 + 2/2) / 3 = 0.78333 。

示例 2:

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

提示:

  • 1 <= classes.length <= 105
  • classes[i].length == 2
  • 1 <= passi <= totali <= 105
  • 1 <= extraStudents <= 105

代码

#include <stdlib.h>

double maxAverageRatio(int** classes, int classesSize, int* classesColSize, int extraStudents) {
    if (classesSize == 0) return 0.0;
    
    // 初始化存储每个班级通过人数和总人数的数组
    int* passes = (int*)malloc(classesSize * sizeof(int));
    int* totals = (int*)malloc(classesSize * sizeof(int));
    for (int i = 0; i < classesSize; i++) {
        passes[i] = classes[i][0];
        totals[i] = classes[i][1];
    }
    
    // 定义堆节点结构(存储负增益和班级索引)
    typedef struct {
        double neg_gain;
        int idx;
    } HeapNode;
    
    HeapNode* heap = (HeapNode*)malloc(classesSize * sizeof(HeapNode));
    int heapSize = 0;
    
    // 初始化堆:计算每个班级的初始增益并插入堆
    for (int i = 0; i < classesSize; i++) {
        int pass = passes[i];
        int total = totals[i];
        double gain = 0.0;
        if (total > pass) {
            gain = (double)(total - pass) / ((double)total * (total + 1));
        }
        // 插入堆(使用负增益构建最小堆)
        int cur = heapSize++;
        heap[cur].neg_gain = -gain;
        heap[cur].idx = i;
        // 上浮操作维护堆性质
        while (cur > 0) {
            int parent = (cur - 1) / 2;
            if (heap[parent].neg_gain > heap[cur].neg_gain) {
                HeapNode temp = heap[parent];
                heap[parent] = heap[cur];
                heap[cur] = temp;
                cur = parent;
            } else break;
        }
    }
    
    // 分配额外学生
    for (int k = 0; k < extraStudents; k++) {
        // 提前终止:若堆顶增益接近0(无法再提升)
        if (-heap[0].neg_gain < 1e-9) break;
        
        // 弹出堆顶元素(增益最大的班级)
        HeapNode top = heap[0];
        heap[0] = heap[--heapSize];
        // 下沉操作维护堆性质
        int cur = 0;
        while (1) {
            int left = 2 * cur + 1;
            int right = 2 * cur + 2;
            int smallest = cur;
            if (left < heapSize && heap[left].neg_gain < heap[smallest].neg_gain) {
                smallest = left;
            }
            if (right < heapSize && heap[right].neg_gain < heap[smallest].neg_gain) {
                smallest = right;
            }
            if (smallest != cur) {
                HeapNode temp = heap[cur];
                heap[cur] = heap[smallest];
                heap[smallest] = temp;
                cur = smallest;
            } else break;
        }
        
        // 更新该班级数据
        int idx = top.idx;
        passes[idx]++;
        totals[idx]++;
        
        // 重新计算增益
        double new_gain = 0.0;
        int new_pass = passes[idx];
        int new_total = totals[idx];
        if (new_total > new_pass) {
            new_gain = (double)(new_total - new_pass) / ((double)new_total * (new_total + 1));
        }
        
        // 重新插入堆
        int cur_index = heapSize++;
        heap[cur_index].neg_gain = -new_gain;
        heap[cur_index].idx = idx;
        while (cur_index > 0) {
            int parent = (cur_index - 1) / 2;
            if (heap[parent].neg_gain > heap[cur_index].neg_gain) {
                HeapNode temp = heap[parent];
                heap[parent] = heap[cur_index];
                heap[cur_index] = temp;
                cur_index = parent;
            } else break;
        }
    }
    
    // 计算平均通过率
    double total_rate = 0.0;
    for (int i = 0; i < classesSize; i++) {
        total_rate += (double)passes[i] / (double)totals[i];
    }
    double average = total_rate / classesSize;
    
    // 释放内存
    free(passes);
    free(totals);
    free(heap);
    
    return average;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值