Maximize Happiness of Selected Children
MedPrompt
You are given an array happiness of length n, and a positive integer k.
There are n children standing in a queue, where the ith child has happiness value happiness[i]. You want to select k children from these n children in k turns.
In each turn, when you select a child, the happiness value of all the children that have not been selected till now decreases by 1. Note that the happiness value cannot become negative and gets decremented only if it is positive.
Return the maximum sum of the happiness values of the selected children you can achieve by selecting k children.
Example 1:
Input: happiness = [1,2,3], k = 2
Output: 4
Explanation: We can pick 2 children in the following way:
- Pick the child with the happiness value == 3. The happiness value of the remaining children becomes [0,1].
- Pick the child with the happiness value == 1. The happiness value of the remaining child becomes [0]. Note that the happiness value cannot become less than 0.
The sum of the happiness values of the selected children is 3 + 1 = 4.Example 2:
Input: happiness = [1,1,1,1], k = 2
Output: 1
Explanation: We can pick 2 children in the following way:
- Pick any child with the happiness value == 1. The happiness value of the remaining children becomes [0,0,0].
- Pick the child with the happiness value == 0. The happiness value of the remaining child becomes [0,0].
The sum of the happiness values of the selected children is 1 + 0 = 1.Example 3:
Input: happiness = [2,3,4,5], k = 1
Output: 5
Explanation: We can pick 1 child in the following way:
- Pick the child with the happiness value == 5. The happiness value of the remaining children becomes [1,2,3].
The sum of the happiness values of the selected children is 5.
Constraints:
1 <= n == happiness.length <= 2 * 1051 <= happiness[i] <= 1081 <= k <= n
Approaches
3 approaches with complexity analysis and trade-offs.
This approach directly simulates the process described in the problem. In each of the k turns, we find the child with the highest current happiness, add their happiness to our total, and then update the happiness of all remaining children by decrementing their values by one.
Algorithm
-
- Convert the input array
happinessinto a mutable list, for instance, anArrayList.
- Convert the input array
-
- Initialize a variable
totalHappinessto 0.
- Initialize a variable
-
- Loop
ktimes to simulate thekturns.
- Loop
-
- In each turn:
- a. Find the child with the maximum current happiness in the list. This requires a linear scan.
- b. Add this maximum happiness value to
totalHappiness. - c. Remove the selected child from the list.
- d. Iterate through all remaining children in the list and decrement their happiness by 1. Ensure no happiness value drops below zero.
-
- After
kturns, returntotalHappiness.
- After
Walkthrough
The naive simulation involves maintaining a list of the current happiness values of all available children. In a loop that runs k times, we perform three main operations: find the maximum value, remove it, and update the rest. Finding the maximum requires iterating through the list, which takes O(N) time, where N is the current number of children. Removing an element from a list can also take O(N). Finally, updating the N-1 remaining children takes another O(N). Since these operations are nested inside a loop that runs k times, the overall complexity becomes prohibitive for large inputs.
import java.util.ArrayList;import java.util.Collections;import java.util.List; class Solution { public long maximumHappinessSum(int[] happiness, int k) { List<Integer> happinessList = new ArrayList<>(); for (int h : happiness) { happinessList.add(h); } long totalHappinessSum = 0; int turns = 0; for (int i = 0; i < k; i++) { if (happinessList.isEmpty()) { break; } // Find and remove the child with max happiness int maxHappiness = 0; int maxIndex = -1; for (int j = 0; j < happinessList.size(); j++) { if (happinessList.get(j) > maxHappiness) { maxHappiness = happinessList.get(j); maxIndex = j; } } if (maxIndex == -1) { // All remaining happiness are 0 // Find any element to remove if(!happinessList.isEmpty()) maxIndex = 0; else break; } totalHappinessSum += happinessList.get(maxIndex); happinessList.remove(maxIndex); // Update happiness of remaining children for (int j = 0; j < happinessList.size(); j++) { if (happinessList.get(j) > 0) { happinessList.set(j, happinessList.get(j) - 1); } } } return totalHappinessSum; }}Note: The provided simulation code is not fully correct because it decrements happiness values based on their current value, not their value at the start of the turn. A correct simulation is more complex, but any direct simulation will face the same performance issues. The greedy approach is the way to go.
Complexity
Time
O(n * k). In each of the `k` turns, we iterate through the list of up to `n` children to find the max and then again to update their values. This results in a quadratic time complexity in the worst case (when `k` is close to `n`).
Space
O(n) to store the happiness values in a separate list.
Trade-offs
Pros
Conceptually simple and easy to understand as it directly follows the problem statement.
Cons
Extremely inefficient due to repeated linear scans of the list.
The time complexity of
O(n*k)makes it too slow for the given constraints, leading to a 'Time Limit Exceeded' error on most platforms.
A more efficient approach comes from a greedy strategy. We can observe that to maximize the total happiness, we should always prioritize selecting children with the highest initial happiness. The penalty for selecting a child later is fixed by the turn number. By sorting the happiness array, we can easily pick the top k children in an optimal sequence (from highest initial happiness to lowest).
Algorithm
-
- The key insight is that the total happiness is maximized by picking the children with the highest initial happiness values first.
-
- The happiness contributed by a child selected at
turni(0-indexed) isinitial_happiness - i.
- The happiness contributed by a child selected at
-
- To maximize the sum, we should pair the largest
initial_happinesswith the smallest decrement (i=0), the second largest with the next smallest (i=1), and so on.
- To maximize the sum, we should pair the largest
-
- Sort the
happinessarray in ascending order.
- Sort the
-
- Initialize
totalHappiness(as alongto prevent overflow) to 0 andturnsto 0.
- Initialize
-
- Iterate from the end of the sorted array for
kelements (from indexn-1down ton-k).
- Iterate from the end of the sorted array for
-
- In each step, calculate the effective happiness:
happiness[i] - turns.
- In each step, calculate the effective happiness:
-
- If the effective happiness is positive, add it to
totalHappiness. Otherwise, we can stop, as subsequent children will yield no happiness.
- If the effective happiness is positive, add it to
-
- Increment
turnsand continue to the next child.
- Increment
-
- Return
totalHappiness.
- Return
Walkthrough
The logic is that the total sum we want to maximize is (h_1 - 0) + (h_2 - 1) + ... + (h_k - (k-1)), where h_1, h_2, ..., h_k are the initial happiness values of the selected children. To make this sum as large as possible, we must assign the largest happiness values to the terms with the smallest subtractions. This is achieved by picking the child with the highest initial happiness at turn 0, the second-highest at turn 1, and so on.
This leads to a simple algorithm: sort the array and iterate through the k largest elements, calculating their contribution at each turn.
import java.util.Arrays; class Solution { public long maximumHappinessSum(int[] happiness, int k) { // Sort the array to easily access the children with the highest happiness. Arrays.sort(happiness); long totalHappinessSum = 0; int n = happiness.length; int turns = 0; // Iterate from the child with the highest happiness. for (int i = n - 1; i >= n - k; i--) { // Calculate the current happiness of the child. // It decreases by 1 for each turn that has passed. long currentHappiness = happiness[i] - turns; // If the happiness is positive, add it to the sum. if (currentHappiness > 0) { totalHappinessSum += currentHappiness; } else { // If the current happiness is not positive, the happiness of the // remaining children (which is less than or equal to the current one) // will also not be positive after decrementing. So we can stop early. break; } // Increment the number of turns for the next child. turns++; } return totalHappinessSum; }}Complexity
Time
O(n log n), dominated by the time it takes to sort the entire `happiness` array. The subsequent loop runs at most `k` times, which is `O(k)`.
Space
O(log n) or O(n), depending on the implementation of the sorting algorithm. Java's `Arrays.sort` for primitives uses a variant of quicksort, which has an average space complexity of `O(log n)`.
Trade-offs
Pros
Significantly more efficient than the naive simulation.
Correct and guaranteed to pass within the given constraints.
Simple to implement using standard library sorting functions.
Cons
Sorting the entire array is
O(n log n), which can be suboptimal ifkis much smaller thann.
This approach refines the greedy strategy by using a more suitable data structure. Since we only need to repeatedly find the maximum of the remaining elements, a max-heap is a perfect fit. It avoids the cost of fully sorting the array, which is unnecessary if we only select a small subset of children (k << n).
Algorithm
-
- The underlying greedy strategy is the same: pick the
kchildren with the highest initial happiness.
- The underlying greedy strategy is the same: pick the
-
- Instead of sorting the whole array, use a max-heap (in Java, a
PriorityQueuewith a reverse order comparator) to efficiently access the maximum element.
- Instead of sorting the whole array, use a max-heap (in Java, a
-
- Build the max-heap from all the
happinessvalues. This can be done inO(n)time.
- Build the max-heap from all the
-
- Initialize
totalHappinessto 0 andturnsto 0.
- Initialize
-
- Loop
ktimes:
- a. Extract the maximum element (
h) from the heap. - b. Calculate the effective happiness:
h - turns. - c. If it's positive, add it to
totalHappiness. - d. If it's zero or less, break the loop early for the same reason as in the sorting approach.
- e. Increment
turns.
- Loop
-
- Return
totalHappiness.
- Return
Walkthrough
A max-heap allows us to find the maximum element in O(1) time (peeking) and remove it in O(log n) time. We can build a heap from the n happiness values in O(n) time. Then, we perform k extractions, each taking O(log n) time. This leads to a total time complexity that is better than full sorting when k is small.
import java.util.Collections;import java.util.PriorityQueue; class Solution { public long maximumHappinessSum(int[] happiness, int k) { // Create a max-heap to store happiness values. PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder()); for (int h : happiness) { maxHeap.add(h); } long totalHappinessSum = 0; int turns = 0; for (int i = 0; i < k; i++) { // Get the child with the current maximum happiness. int maxHappiness = maxHeap.poll(); // Calculate their happiness at the moment of selection. long currentHappiness = maxHappiness - turns; if (currentHappiness > 0) { totalHappinessSum += currentHappiness; } else { // If the highest happiness child gives 0 or less, the rest will too. break; } turns++; } return totalHappinessSum; }}Complexity
Time
O(n + k log n). Building the heap by adding `n` elements one by one takes `O(n log n)`. A more optimized build (e.g., `addAll` from a collection) takes `O(n)`. Then, we perform `k` poll operations, each taking `O(log n)` time.
Space
O(n) to store the `n` elements in the `PriorityQueue`.
Trade-offs
Pros
Asymptotically more efficient than sorting, with a time complexity of
O(n + k log n).Particularly effective when
kis much smaller thann.
Cons
Requires
O(n)extra space for the heap, whereas an in-place sort might use less.The constant factors for heap operations might be higher than for a highly optimized array sort, potentially making it slower in practice unless
kis significantly smaller thann.
Solutions
Solution
class Solution {public long maximumHappinessSum(int[] happiness, int k) { Arrays.sort(happiness); long ans = 0; for (int i = 0, n = happiness.length; i < k; ++i) { int x = happiness[n - i - 1] - i; ans += Math.max(x, 0); } return ans; }}class Solution: def maximumHappinessSum(self, happiness: List[int], k: int) -> int: happiness . sort(reverse=True) ans = 0 for i, x in enumerate(happiness[: k]): x -= i ans += max(x, 0) return ansclass Solution {public: long long maximumHappinessSum(vector<int> &happiness, int k) { sort(happiness.rbegin(), happiness.rend()); long long ans = 0; for (int i = 0, n = happiness.size(); i < k; ++i) { int x = happiness[i] - i; ans += max(x, 0); } return ans; }};Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.