Leetcode Question Link

For the convenience, we use to denote in article below.

Analysis

Gain From One Child

Consider if we chose children at time , what could we add to the final sum?

If not considering our choice, the lost of the happiness should be:

  • If , this means the will goes to before the procedure finished, so the maximum decrease of the value is from to , that is,
  • If , that means never reach , the decrease value is exactly the round . So we have .

Now take our choice operation into consideration. If we chose a child at time , then the actual lost of happiness of this child should be:

  • If , means we chose this child while it’s decreasing, this means if we chose this child, it should be decreasing from time to time , the actual decrease value .
  • If , means this child’s happiness already stop decreasing, our action of choice actually has no effect, so .

In conclusion, we could know that for any child , if we choice it, the happiness value we could get will be:

Choose Child

Based on analysis above, we should be aware that the greedy strategy could be used for this question. That is, to ensure highest final sum, we should always choose child with largest initial happiness first.

Consider the formula of :

If we want to make larger, we need to make smaller, so we should put larger with smaller . And that, in this problem, means choose child with larger happiness sooner.

Code

#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
 
using std::priority_queue;
using std::vector;
 
bool debug = false;
 
struct MyMinHeap : std::priority_queue<int, std::vector<int>, std::greater<int>> {
    void reserve(size_t n) { this->c.reserve(n); }
};
 
class Solution {
public:
    long long maximumHappinessSum(vector<int>& happiness, int k) {
        // min heap
        MyMinHeap maxk;
        maxk.reserve(k);
        int cur, top;
 
        // initial heap with k elements
        for (int i = 0; i < k; ++i) {
            maxk.push(happiness[i]);
        }
        // iterate while update
        for (int i = k; i < happiness.size(); ++i) {
            cur = happiness[i];
            top = maxk.top();
 
            // current elements smaller, just continue
            if (cur <= top) {
                continue;
            }
            // update elements
            maxk.pop();
            maxk.push(cur);
        }
 
        // at this point, all max-k elements are in the min heap
 
        long long answer = 0;
        int chooseTime, lost;
        for (chooseTime = k - 1; chooseTime >= 0; --chooseTime) {
            // get top element
            cur = maxk.top();
            maxk.pop();
 
            if (debug) {
                cout << "choosed: " << cur << endl;
            }
 
            // determine the lost of this element
            lost = std::min({k, cur, chooseTime});
 
            // update answer
            answer += (cur - lost);
        }
 
        return answer;
    }
};