[JS] Greedy Heap O(M log N) O(N)
javascript\nvar maxAverageRatio = function(classes, extraStudents) {\n    // the heap will automatically find the class that will benefit\n    // the most by ad
```javascript\nvar maxAverageRatio = function(classes, extraStudents) {\n    // the heap will automatically find the class that will benefit\n    // the most by adding a passing student\n    const heap = new MaxHeap();\n    \n    // push all the classes into the heap so that\n    // the heap can find the class that will benefit the most\n    for (const x of classes) {\n        heap.push(x);\n    }\n    \n    // while there are extra students\n    while (extraStudents) {\n        \n        // add the extra student to the class that will benefit the most\n        heap.peak()[0] += 1;\n        heap.peak()[1] += 1;\n        \n        // heapify down so that the heap remains valid\n        heap.heapifyDown(0);\n        \n        extraStudents--;\n    }\n    \n    \n    // calculate the new average of all the classes\n    let total = 0;\n    for (const [x , y] of heap.store) {\n        total += (x / y);\n    }\n    return total / heap.store.length;\n};\n\n\nclass MaxHeap {\n    constructor() {\n        this.store = [];\n    }\n    \n    peak() {\n        return this.store[0];\n    }\n    \n    size() {\n        return this.store.length;\n    }\n    \n    pop() {\n        if (this.store.length < 2) {\n            return this.store.pop();\n        }\n        const result = this.store[0];\n        this.store[0] = this.store.pop();\n        this.heapifyDown(0);\n        return result;\n    }\n    \n    push(val) {\n        this.store.push(val);\n        this.heapifyUp(this.store.length - 1);\n    }\n    \n    heapifyUp(child) {\n        while (child) {\n            const parent = Math.floor((child - 1) / 2);\n            if (this.shouldSwap(child, parent)) {\n                [this.store[child], this.store[parent]] = [this.store[parent], this.store[child]]\n                child = parent;\n            } else {\n                return child;\n            }\n        }\n    }\n    \n    heapifyDown(parent) {\n        while (true) {\n            let [child, child2] = [1,2].map((x) => parent * 2 + x).filter((x) => x < this.size());\n            if (this.shouldSwap(child2, child)) {\n                child = child2\n            }\n            if (this.shouldSwap(child, parent)) {\n                [this.store[child], this.store[parent]] = [this.store[parent], this.store[child]]\n                parent = child;\n            } else {\n                return parent;\n            }\n        }\n    }\n    \n    shouldSwap(child, parent) {\n        if (!child) return false;\n        const c = (this.store[child][0] + 1) / (this.store[child][1] + 1) - (this.store[child][0]) / (this.store[child][1]);\n        const p = (this.store[parent][0] + 1) / (this.store[parent][1] + 1) - (this.store[parent][0]) / (this.store[parent][1]);\n        return c > p;\n    }\n}\n```
['Heap (Priority Queue)', 'JavaScript']