3075. Maximize Happiness of Selected Children


Problem Description

In this problem, we are presented with n children standing in a queue, each with a certain "happiness" value. We aim to maximize the total happiness by selecting k children. Notably, each time a child is chosen, the happiness value of every unselected child decreases by 1, if their happiness is positive. The challenge is that as we select children, the unselected ones become less happy, so we need to carefully pick the sequence to make the most out of the happiness we can gather. The goal is to devise a strategy to get the maximum sum of happiness values by selecting k children from the queue.

Intuition

To maximize the total happiness from selecting k children, we need to grab the opportunity of the highest happiness values first. One optimal strategy is to prioritize children with higher happiness values before their potential happiness diminishes due to the selection of others. This calls for a greedy approach where sorting comes to play a vital role.

By sorting the children in descending order based on their happiness, we ensure that we select the happiest child first. Remember, each time we pick a child, subsequent children's happiness reduces by 1—but only if they're still positive. So, we greedily select from the top, decrementing the happiness value by the number of children already selected, symbolized by i.

The solution approach involves:

  1. Sorting the children based on their happiness values in descending order.
  2. Iteratively selecting k children from the sorted list.
  3. For each selected child, computing the effective happiness as the current happiness minus the count of previously selected children.
  4. Ensuring that if decrementing makes the happiness value negative, we consider it as zero since happiness cannot be negative by the problem's constraint.
  5. Summing up all the effective happiness values of the selected children to achieve the maximum sum.

Implementing this approach yields the maximum sum of happiness we can obtain from the given queue of children.

Learn more about Greedy and Sorting patterns.

Not Sure What to Study? Take the 2-min Quiz to Find Your Missing Piece:

How does quick sort divide the problem into subproblems?

Solution Approach

To implement the solution effectively, we use the following algorithmic steps and Python built-in features aligned with the Greedy approach and the specified behavior of the problem:

  1. Sorting: We start by sorting the happiness array in descending order. This is crucial because we want to select children with higher happiness values first, as each selection will decrease the potential happiness we can collect from the remaining children.

    1happiness.sort(reverse=True)

    By sorting in reverse order, we guarantee that happiness[0] holds the highest value, happiness[1] the second-highest, and so on.

  2. Iterative Selection: We iterate over the first k children in the sorted happiness array. This is because, according to our Greedy strategy, these will be the children from whom we can extract the most happiness before their values start to decrease.

    1for i, x in enumerate(happiness[:k]):

    Here, enumerate is a built-in Python function that provides both the index i and the value x during the iteration. The index i represents how many children have been previously selected and thus by how much the currently considered child's happiness will be reduced.

  3. Happiness Calculation and Summation:

    • We calculate the adjusted happiness for each selected child. The adjustment is based on the assumption that each child's happiness decreases by 1 for every child already selected, which corresponds to the index i.

    • We use the max function to ensure that we do not consider negative happiness values because the problem states that happiness cannot be negative even after decrementing.

    1x -= i
    2ans += max(x, 0)

    The adjusted happiness (x - i) is added to the ans, which accumulates the total happiness over the selection of k children.

  4. Returning the Result: After processing the k children, we have the maximum sum of happiness in ans, which we return as the result.

    1return ans

Altogether, the algorithm uses sorting and a single pass through the first k elements of the sorted array to compute the maximum sum of happiness. The Greedy approach ensures that, at each step, we make the locally optimal choice by picking the child with the maximum possible happiness at that turn.

Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:

Which data structure is used to implement recursion?

Example Walkthrough

Let's walk through an example to demonstrate the solution approach. Suppose we have n = 5 children with happiness values given by the array happiness = [5, 3, 1, 2, 4], and we want to maximize the total happiness by selecting k = 3 children from the queue.

Here are the steps we’ll follow, as per the solution approach:

Step 1: Sorting First, we sort the happiness array in descending order:

1happiness.sort(reverse=True)  # [5, 4, 3, 2, 1]

Now, the happiness array becomes [5, 4, 3, 2, 1].

Step 2: Iterative Selection Next, we iterate over the first k children in the sorted happiness array. Applying the Greedy strategy, we’ll pick the children with the highest happiness first:

1for i, x in enumerate(happiness[:3]):  # i goes from 0 to 2, x will be 5, then 4, then 3

Step 3: Happiness Calculation and Summation On each iteration, we calculate the effective happiness (x - i) and ensure it does not go below zero:

  • First iteration (i = 0, x = 5): x - i is 5 - 0, which equals 5. So we add 5 to the total happiness.
  • Second iteration (i = 1, x = 4): x - i is 4 - 1, which equals 3. We add 3 to the total happiness.
  • Third iteration (i = 2, x = 3): x - i is 3 - 2, which equals 1. We add 1 to the total happiness.

The ans keeps accumulating these values, and we use the max function to add only non-negative values:

1ans = 0
2ans += max(5 - 0, 0)  # ans = 5
3ans += max(4 - 1, 0)  # ans = 5 + 3 = 8
4ans += max(3 - 2, 0)  # ans = 8 + 1 = 9

Step 4: Returning the Result After processing k = 3 children, we have the total happiness:

1return ans  # returns 9

The resulting maximum sum of happiness values for selecting k = 3 children is 9. The selection process prioritized children with the highest happiness value first and adjusted for each subsequent selection. This example confirms that our Greedy approach effectively maximizes the total happiness achieved.

Solution Implementation

1class Solution:
2    def maximumHappinessSum(self, happiness: List[int], k: int) -> int:
3        # Sort the happiness values in descending order.
4        happiness.sort(reverse=True)
5        max_happiness = 0 # Initialize the maximum happiness sum.
6
7        # Loop through the first k elements after sorting.
8        for i in range(k):
9            # Since a person’s happiness value can decrease with each additional person,
10            # we subtract the current index from the happiness value,
11            # however, we should not go below 0.
12            decreased_happiness = happiness[i] - i
13            if decreased_happiness > 0:
14                max_happiness += decreased_happiness
15
16        # Return the sum of the maximized happiness values.
17        return max_happiness
18
1class Solution {
2    public long maximumHappinessSum(int[] happiness, int k) {
3        // Sort the array so that we can easily pick the largest elements
4        Arrays.sort(happiness);
5
6        // Initialize the sum of happiness to 0
7        long totalHappiness = 0;
8
9        // Iterate through the array starting from the end to get the largest values
10        for (int i = 0; i < k; ++i) {
11            // Calculate the current happiness after decrementing based on index i
12            // Using n - i - 1 to pick the k largest elements in a sorted array
13            int currentHappiness = happiness[happiness.length - i - 1] - i;
14          
15            // Sum only the positive values of current happiness after the decrement
16            totalHappiness += Math.max(currentHappiness, 0);
17        }
18
19        // Return the total happiness calculation
20        return totalHappiness;
21    }
22}
23
1#include <vector>
2#include <algorithm> // Include algorithm header for std::sort
3
4class Solution {
5public:
6    // Function to calculate the maximum happiness sum using the provided happiness vector and integer k
7    long long maximumHappinessSum(vector<int>& happiness, int k) {
8        // Sort the happiness vector in non-increasing order
9        sort(happiness.rbegin(), happiness.rend());
10      
11        // Initialize a variable to store the accumulated maximum happiness sum
12        long long maxHappinessSum = 0;
13      
14        // Iterate over the first k elements of the sorted vector
15        for (int i = 0, n = happiness.size(); i < k; ++i) {
16            // Calculate the modified happiness value by subtracting the index
17            int modifiedHappiness = happiness[i] - i;
18          
19            // If the modified happiness value is positive, add it to the sum
20            // Otherwise, add zero (do not decrease the sum)
21            maxHappinessSum += std::max(modifiedHappiness, 0);
22        }
23
24        // Return the accumulated maximum happiness sum
25        return maxHappinessSum;
26    }
27};
28
1// This function calculates the maximum happiness sum from an array of happiness points.
2// It considers the 'k' people with the highest happiness points after applying a specific penalty.
3// The penalty subtracts the person's index from their happiness points (starting from 0).
4
5function maximumHappinessSum(happiness: number[], k: number): number {
6    // Sort the happiness array in descending order.
7    happiness.sort((a, b) => b - a);
8    // Initialize a variable to keep track of the total happiness sum.
9    let totalHappiness = 0;
10
11    // Loop through the first 'k' elements in the sorted happiness array.
12    for (let i = 0; i < k; ++i) {
13        // Calculate the penalty by subtracting the index (0-based) from the happiness points.
14        const penalizedHappiness = happiness[i] - i;
15        // Add the greater of penalizedHappiness or 0 to the totalHappiness sum
16        // to ensure that negative values do not reduce the overall happiness.
17        totalHappiness += Math.max(penalizedHappiness, 0);
18    }
19    // Return the total happiness sum after processing the first 'k' elements.
20    return totalHappiness;
21}
22
Not Sure What to Study? Take the 2-min Quiz:

In a binary min heap, the maximum element can be found in:

Time and Space Complexity

The time complexity of the maximumHappinessSum function is composed of two parts: sorting the happiness list and iterating over a slice of this list.

  • Sorting the list requires O(n * log n) time, where n is the length of the happiness list. The Python sort() method uses the Timsort algorithm, which has this complexity.
  • Iterating over the first k elements of the sorted list takes O(k) time, because we're only looking at a subset of the list, which contains k elements.

Adding these two components together, the total time complexity is O(n * log n + k).

As for the space complexity, the sort operation can be done in-place, but Timsort requires additional temporary space for its operation. This temporary space is O(log n) because of the way the algorithm divides the list and merges sorted sublists. There is no additional significant space usage since only a few extra variables are created, and these do not depend on the size of the input list.

Learn more about how to find time and space complexity quickly using problem constraints.

Fast Track Your Learning with Our Quick Skills Quiz:

Which algorithm is best for finding the shortest distance between two points in an unweighted graph?


Recommended Readings


Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


TA 👨‍🏫