3075. Maximize Happiness of Selected Children
Problem Description
You have an array happiness
of length n
representing the happiness values of n
children standing in a queue. You need to select exactly k
children from this queue to maximize the total happiness sum.
The selection process works as follows:
- You select children one by one over
k
turns - When you select a child in any turn, you add their current happiness value to your total
- After each selection, all remaining unselected children have their happiness values decreased by 1
- Happiness values cannot go below 0 (if a child's happiness would become negative, it stays at 0)
For example, if you have children with happiness [5, 3, 2]
and you select the first child (happiness = 5), the remaining children's happiness becomes [2, 1]
(each decreased by 1).
Your goal is to find the maximum possible sum of happiness values you can achieve by strategically selecting k
children.
The solution uses a greedy approach: sort the children by happiness in descending order and select them in that order. When selecting the i
-th child (0-indexed), their contribution to the total will be max(happiness[i] - i, 0)
because i
represents how many selections have already been made before this child.
Intuition
The key insight is that every time we select a child, all remaining children lose 1 happiness point. This creates a "decay effect" - the longer a child waits to be selected, the more their happiness decreases.
To maximize our total, we want to minimize the impact of this decay. Think about it this way: if we have a child with happiness 10 and another with happiness 3, which should we select first? If we select the child with happiness 3 first:
- We get 3 points immediately
- The child with happiness 10 becomes 9 for the next turn
- Total: 3 + 9 = 12
But if we select the child with happiness 10 first:
- We get 10 points immediately
- The child with happiness 3 becomes 2 for the next turn
- Total: 10 + 2 = 12
Wait, they're the same? Not quite! Consider a third child with happiness 7. If we pick in order 3, 10, 7:
- Turn 1: Get 3, others become [9, 6]
- Turn 2: Get 9, other becomes [5]
- Turn 3: Get 5
- Total: 3 + 9 + 5 = 17
But if we pick in order 10, 7, 3:
- Turn 1: Get 10, others become [6, 2]
- Turn 2: Get 6, other becomes [1]
- Turn 3: Get 1
- Total: 10 + 6 + 1 = 17
Still the same? Let's try 10, 7, 3 with initial values [10, 8, 2]:
- Picking 2, 10, 8: Total = 2 + 9 + 6 = 17
- Picking 10, 8, 2: Total = 10 + 7 + 0 = 17
Actually, the order matters when happiness values can drop to 0! Children with lower initial happiness are more vulnerable to becoming 0 if they wait. By selecting children with higher happiness first, we "save" their larger values before decay affects them, and let the smaller values decay (which matters less since they contribute less anyway).
This naturally leads to the greedy strategy: sort by happiness descending and pick in that order. The i
-th selected child will have waited through i
selections, so their contribution is max(happiness[i] - i, 0)
.
Solution Approach
The solution implements the greedy strategy we identified through the following steps:
Step 1: Sort the happiness array in descending order
happiness.sort(reverse=True)
This ensures we process children with higher happiness values first. Sorting takes O(n log n)
time.
Step 2: Select the first k children and calculate their contributions
ans = 0
for i, x in enumerate(happiness[:k]):
x -= i
ans += max(x, 0)
We iterate through the first k
elements of the sorted array. For each child at index i
:
i
represents how many children we've already selected (0-indexed)- This means
i
turns have passed, so all remaining children have losti
happiness points - The current child's actual happiness when selected is
happiness[i] - i
- We use
max(x, 0)
to ensure we don't add negative values (happiness can't go below 0) - We accumulate the sum in
ans
Time Complexity: O(n log n)
for sorting, plus O(k)
for the iteration, giving us O(n log n)
overall.
Space Complexity: O(1)
if we don't count the space used by sorting (which is typically O(log n)
for the sorting algorithm's recursion stack).
Example walkthrough:
If happiness = [5, 3, 2, 1]
and k = 3
:
- After sorting:
[5, 3, 2, 1]
- Select child 0: happiness = 5 - 0 = 5, sum = 5
- Select child 1: happiness = 3 - 1 = 2, sum = 5 + 2 = 7
- Select child 2: happiness = 2 - 2 = 0, sum = 7 + 0 = 7
The maximum happiness sum is 7.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example with happiness = [4, 6, 1, 5]
and k = 3
.
Initial Setup:
- We have 4 children with happiness values: [4, 6, 1, 5]
- We need to select exactly 3 children
- Remember: each time we select a child, all unselected children lose 1 happiness point
Step 1: Sort in descending order
After sorting: [6, 5, 4, 1]
This greedy ordering ensures we "save" the highest values from decay.
Step 2: Process selections
Selection 1 (i=0):
- Select child with happiness 6
- Since this is the first selection (i=0), no decay has occurred yet
- Contribution: 6 - 0 = 6
- Running sum: 6
- Remaining children's happiness after this selection: [4, 3, 0] (each decreased by 1)
Selection 2 (i=1):
- Select child with original happiness 5
- One selection has already occurred (i=1), so this child has experienced 1 turn of decay
- Contribution: 5 - 1 = 4
- Running sum: 6 + 4 = 10
- Remaining children's happiness after this selection: [2, -1] โ [2, 0] (capped at 0)
Selection 3 (i=2):
- Select child with original happiness 4
- Two selections have already occurred (i=2), so this child has experienced 2 turns of decay
- Contribution: 4 - 2 = 2
- Running sum: 10 + 2 = 12
Final Result: Maximum happiness sum = 12
Notice how the formula max(happiness[i] - i, 0)
elegantly captures the decay effect: each child at position i in our sorted array will have waited through i selections before being chosen, losing i happiness points in the process.
Solution Implementation
1class Solution:
2 def maximumHappinessSum(self, happiness: List[int], k: int) -> int:
3 # Sort the happiness array in descending order to prioritize selecting children with highest happiness
4 happiness.sort(reverse=True)
5
6 # Initialize the total happiness sum
7 total_happiness = 0
8
9 # Iterate through the first k children (those with highest happiness values)
10 for turn_index, happiness_value in enumerate(happiness[:k]):
11 # Each selected child's happiness decreases by the number of children selected before them
12 adjusted_happiness = happiness_value - turn_index
13
14 # Add the adjusted happiness to total (minimum 0 if happiness becomes negative)
15 total_happiness += max(adjusted_happiness, 0)
16
17 return total_happiness
18
1class Solution {
2 public long maximumHappinessSum(int[] happiness, int k) {
3 // Sort the happiness array in ascending order
4 Arrays.sort(happiness);
5
6 // Initialize the total happiness sum
7 long totalHappiness = 0;
8
9 // Get the length of the happiness array
10 int n = happiness.length;
11
12 // Select k children with highest happiness values (from the end of sorted array)
13 for (int i = 0; i < k; i++) {
14 // Calculate the adjusted happiness for the current child
15 // Each previously selected child reduces happiness by 1
16 int adjustedHappiness = happiness[n - i - 1] - i;
17
18 // Add the adjusted happiness to total (minimum 0 if happiness becomes negative)
19 totalHappiness += Math.max(adjustedHappiness, 0);
20 }
21
22 return totalHappiness;
23 }
24}
25
1class Solution {
2public:
3 long long maximumHappinessSum(vector<int>& happiness, int k) {
4 // Sort the happiness array in descending order to prioritize selecting children with higher happiness
5 sort(happiness.rbegin(), happiness.rend());
6
7 // Initialize the total happiness sum
8 long long totalHappiness = 0;
9
10 // Select k children with the highest happiness values
11 for (int i = 0; i < k; ++i) {
12 // Calculate adjusted happiness after i children have already been selected
13 // Each previously selected child reduces current child's happiness by 1
14 int adjustedHappiness = happiness[i] - i;
15
16 // Add the adjusted happiness to total (minimum 0 if happiness becomes negative)
17 totalHappiness += max(adjustedHappiness, 0);
18 }
19
20 return totalHappiness;
21 }
22};
23
1/**
2 * Calculates the maximum happiness sum by selecting k people
3 * @param happiness - Array of happiness values for each person
4 * @param k - Number of people to select
5 * @returns The maximum possible sum of happiness values
6 */
7function maximumHappinessSum(happiness: number[], k: number): number {
8 // Sort the happiness array in descending order to prioritize higher values
9 happiness.sort((a: number, b: number) => b - a);
10
11 // Initialize the total happiness sum
12 let totalHappinessSum: number = 0;
13
14 // Select the top k people with highest happiness values
15 for (let i: number = 0; i < k; ++i) {
16 // Calculate adjusted happiness (original happiness minus the number of people selected before)
17 // Each person selected reduces others' happiness by 1
18 const adjustedHappiness: number = happiness[i] - i;
19
20 // Add the adjusted happiness to total (minimum 0 if happiness becomes negative)
21 totalHappinessSum += Math.max(adjustedHappiness, 0);
22 }
23
24 return totalHappinessSum;
25}
26
Time and Space Complexity
Time Complexity: O(n ร log n + k)
- The
sort()
operation withreverse=True
takesO(n ร log n)
time, wheren
is the length of thehappiness
array - The iteration through the first
k
elements takesO(k)
time - Each operation inside the loop (subtraction, max comparison, and addition) takes
O(1)
time - Therefore, the total time complexity is
O(n ร log n + k)
Space Complexity: O(log n)
- The sorting algorithm (Timsort in Python) uses
O(log n)
space for the recursion stack in the worst case - The slicing operation
happiness[:k]
creates an iterator in the enumerate function, which doesn't create a new list - The variables
ans
,i
, andx
use constantO(1)
space - Therefore, the total space complexity is
O(log n)
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Not Handling Negative Happiness Values
The Problem: A common mistake is forgetting to handle cases where happiness values become negative after decrements. If you simply add happiness[i] - i
without checking if it's negative, you'll get an incorrect (lower) result.
Incorrect Implementation:
def maximumHappinessSum(self, happiness: List[int], k: int) -> int:
happiness.sort(reverse=True)
total = 0
for i in range(k):
total += happiness[i] - i # Wrong! This can subtract when happiness goes negative
return total
Why It's Wrong: If happiness = [2, 1, 1]
and k = 3
:
- Select child 0: 2 - 0 = 2
- Select child 1: 1 - 1 = 0
- Select child 2: 1 - 2 = -1 (incorrectly subtracts 1 from total)
Correct Solution: Always use max(happiness[i] - i, 0)
to ensure non-negative contributions.
Pitfall 2: Early Termination When Encountering Zero Happiness
The Problem: Some might think they should stop selecting children once the adjusted happiness becomes 0, but this could miss opportunities if later children have high enough initial happiness values.
Incorrect Implementation:
def maximumHappinessSum(self, happiness: List[int], k: int) -> int:
happiness.sort(reverse=True)
total = 0
selected = 0
for i, h in enumerate(happiness):
if selected >= k:
break
adjusted = h - i
if adjusted <= 0:
break # Wrong! Should continue checking remaining children
total += adjusted
selected += 1
return total
Why It's Wrong: This breaks too early. Even if one child's adjusted happiness is 0, the next child in the sorted order might still have positive adjusted happiness if their initial value is high enough.
Correct Solution: Always iterate through exactly k
children (or all children if fewer than k
exist) and use max(adjusted, 0)
for each.
Pitfall 3: Modifying the Original Array During Selection
The Problem: Attempting to actually modify the happiness array during selection to reflect the decrements, which complicates the logic unnecessarily.
Incorrect Implementation:
def maximumHappinessSum(self, happiness: List[int], k: int) -> int:
total = 0
for _ in range(k):
max_idx = happiness.index(max(happiness))
total += happiness[max_idx]
happiness.pop(max_idx)
# Decrement all remaining children
for i in range(len(happiness)):
happiness[i] = max(0, happiness[i] - 1)
return total
Why It's Wrong: This approach has O(k*n) time complexity due to repeated max finding and array modifications, and the logic becomes unnecessarily complex.
Correct Solution: Sort once at the beginning and calculate the effective happiness value using the index (which represents the number of prior selections) without modifying the array.
Which of these pictures shows the visit order of a depth-first search?
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Donโt Miss This!