You are given an integer array nums
. You want to maximize the number of points you get by performing the following operation any number of times:
nums[i]
and delete it to earn nums[i]
points. Afterwards, you must delete every element equal to nums[i] - 1
and every element equal to nums[i] + 1
.Return the maximum number of points you can earn by applying the above operation some number of times.
Example 1:
Input: nums = [3,4,2] Output: 6 Explanation: You can perform the following operations: - Delete 4 to earn 4 points. Consequently, 3 is also deleted. nums = [2]. - Delete 2 to earn 2 points. nums = []. You earn a total of 6 points.
Example 2:
Input: nums = [2,2,3,3,3,4] Output: 9 Explanation: You can perform the following operations: - Delete a 3 to earn 3 points. All 2's and 4's are also deleted. nums = [3,3]. - Delete a 3 again to earn 3 points. nums = [3]. - Delete a 3 once more to earn 3 points. nums = []. You earn a total of 9 points.
Constraints:
1 <= nums.length <= 2 * 104
1 <= nums[i] <= 104
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force strategy for this problem involves exploring every possible choice of number selection. We try every combination of taking or skipping each number and then calculating the total score. Finally, we pick the combination that gives us the biggest possible score.
Here's how the algorithm would work step-by-step:
def delete_and_earn_brute_force(numbers):
maximum_score = 0
def calculate_max_score(current_index, current_score, remaining_numbers):
nonlocal maximum_score
if current_index >= len(remaining_numbers):
maximum_score = max(maximum_score, current_score)
return
# Option 1: Skip the current number
calculate_max_score(current_index + 1, current_score, remaining_numbers)
# Option 2: Pick the current number
number_to_pick = remaining_numbers[current_index]
# Create a new list excluding numbers +/- 1 of number_to_pick
new_remaining_numbers = []
# We have to rebuild the list of viable numbers after picking one
for number_index in range(len(remaining_numbers)):
if remaining_numbers[number_index] != number_to_pick - 1 and \
remaining_numbers[number_index] != number_to_pick + 1:
new_remaining_numbers.append(remaining_numbers[number_index])
# Recursive call after picking a number
calculate_max_score(
0, current_score + number_to_pick, new_remaining_numbers
)
calculate_max_score(0, 0, numbers)
return maximum_score
This problem looks complicated, but it's actually a sneaky way to apply a simpler idea. Instead of deleting and earning, we reframe it as a choice: to take a number or leave it, and the earnings become points. This reduces to a common optimization problem.
Here's how the algorithm would work step-by-step:
def delete_and_earn(numbers: list[int]) -> int:
points = {number: 0 for number in numbers}
for number in numbers:
points[number] += number
max_number = max(numbers)
take = 0
skip = 0
# Iterate through all possible numbers.
for current_number in range(1, max_number + 1):
# Decide to either take or skip.
new_take = skip + points.get(current_number, 0)
# Update take/skip values.
new_skip = max(skip, take)
take = new_take
skip = new_skip
# The maximum of take and skip at the end is the answer.
return max(take, skip)
Case | How to Handle |
---|---|
Null or empty input array | Return 0 as there are no elements to earn points from. |
Input array with a single element | Return the value of the single element as that's the maximum possible score. |
Input array with only two elements | Choose the larger element if the difference is greater than 1; otherwise, choose one of them or their sum. |
Large input array with many duplicate elements | The algorithm should scale reasonably well with duplicates because it effectively groups identical values. |
Input array with elements clustered around a specific value | Dynamic programming efficiently explores earning from or skipping each cluster. |
Input array with a wide range of values (e.g., from 0 to 10000) | Using a hash map or frequency array can handle large ranges of non-negative integers efficiently. |
Input contains a very large number of the same integer close to integer limit | Be mindful of potential integer overflow when calculating scores from sums of large integers. |
Negative Numbers Present | The standard solution will not work with negative numbers unless you offset the values to convert them to non-negative. |