Delete and Earn

Updated on 16 May, 2025
Delete and Earn header image

Problem Statement

In this problem, you are provided with an array of integers named nums. Your objective is to maximize the number of points you accumulate by repeatedly performing a specific operation. The operation involves selecting an item nums[i] from the array, deleting it, and earning points equal to the value of nums[i]. However, the operation comes with a constraint: upon picking and deleting nums[i], every other element in the array that has a value of either nums[i]-1 or nums[i]+1 must also be deleted immediately, although they do not contribute to the point score. The challenge is to determine the maximum total points that can be achieved by applying this operation as many times as needed. The problem demands a solution that does not simply involve maximizing point gain in each step but rather maximizing the total gain by strategically choosing elements for deletion, accounting for their surrounding impacts.

Examples

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

Approach and Intuition

The key to solving this problem efficiently lies in recognizing that it resembles the "house robber" problem, where one cannot rob two adjacent houses. Here, points from two adjacent numbers in sorted order cannot be taken together.

  1. Dynamic Programming for Optimized Point Collection:

    • Convert the task into a dynamic programming problem where the state represents the maximum points obtainable from the first i unique numbers.
    • Utilize a hashmap or an array to keep track of the total points available from each unique number in nums by summing occurrences of each number.
    • Create a DP array dp where dp[i] will represent the maximum score obtainable using numbers from 1 to i.
  2. Base Cases and Transitions:

    • If only one number is available (k), then the maximum points are simply the total value of all occurrences of that number.
    • For each number k encountered in nums, relate its value to either taking k (and not taking k-1) or not taking k at all. This relationship is described by the equation:
      • dp[k] = max(dp[k-1], dp[k-2] + k * count[k]) Where dp[k-1] is the maximum points without taking k and dp[k-2] + k * count[k] symbolizes taking the k value into account along with the points from k taking its frequency into consideration and excluding k-1.
  3. Iterating through Possibilities:

    • To ensure all bases are covered, iterate from the lowest to the highest number found in nums, applying the above recurrence to fill the dp array.
  4. Return the Result:

    • The answer to the problem would then be found in dp[x] where x is the maximum value in nums.

By following this approach, where we use dynamic programming to balance between choosing numbers and maximizing points, we can efficiently achieve the solution to the problem, even for large arrays. The examples provided illustrate how this strategy plays out with different configurations of nums.

Solutions

  • Java
  • Python
java
class Solution {
    public int removeAndProfit(int[] elements) {
        int highestValue = 0;
        HashMap<Integer, Integer> valueMap = new HashMap<>();

        for (int element : elements) {
            valueMap.put(element, valueMap.getOrDefault(element, 0) + element);
            highestValue = Math.max(highestValue, element);
        }

        int prevPrevMax = 0;
        int prevMax = 0;
        int n = valueMap.size();

        if (highestValue < n + n * Math.log(n) / Math.log(2)) {
            prevMax = valueMap.getOrDefault(1, 0);
            for (int curr = 2; curr <= highestValue; curr++) {
                int temp = prevMax;
                prevMax = Math.max(prevMax, prevPrevMax + valueMap.getOrDefault(curr, 0));
                prevPrevMax = temp;
            }
        } else {
            List<Integer> sortedKeys = new ArrayList<Integer>(valueMap.keySet());
            Collections.sort(sortedKeys);
            prevMax = valueMap.get(sortedKeys.get(0));

            for (int i = 1; i < sortedKeys.size(); i++) {
                int key = sortedKeys.get(i);
                int tmp = prevMax;
                if (key == sortedKeys.get(i - 1) + 1) {
                    prevMax = Math.max(prevMax, prevPrevMax + valueMap.get(key));
                } else {
                    prevMax += valueMap.get(key);
                }

                prevPrevMax = tmp;
            }
        }

        return prevMax;
    }
}

The Java solution titled "Delete and Earn" involves achieving maximum profit by removing numbers from an array based on the sum of the same numbers. This Java code defines a method removeAndProfit that accepts an array of integers and returns the maximum profit obtained. Follow the outlined logic in understanding the implementation:

  1. Initialize a highestValue to store the maximum element from the array.
  2. Use a HashMap, valueMap, to keep track of cumulative values of each unique element in the input array.
  3. Populate these two by iterating over the elements array.

To determine the maximum points achievable:

  1. Initialize two variables, prevPrevMax and prevMax, to help track the best score while iterating through possible numbers.
  2. Compare highestValue with another calculated condition to decide the approach:
    • If highestValue is less than the logarithm-based condition, iterate linearly from 2 up to highestValue. Update prevMax and prevPrevMax accordingly to get the maximum profit without selecting two adjacent numbers.
    • If not, sort the keys of the valueMap, and apply dynamic programming using sorted keys, updating prevMax and prevPrevMax based on adjacent keys comparison.
  3. Return prevMax as the solution for maximum profit after evaluating all possible cases.

Carefully designed to optimize performance based on the size and range of the input array, this approach leverages dynamic programming and condition-based strategy to efficiently solve the problem ensuring neither excessively consuming resources nor missing out on higher profits available through combined non-adjacent selections.

python
class Solution:
    def removeAndAccumulate(self, numbers: List[int]) -> int:
        score = defaultdict(int)
        maximum_value = 0
        for value in numbers:
            score[value] += value
            maximum_value = max(maximum_value, value)
        
        prev_two = prev_one = 0
        count = len(score)
        if maximum_value < count + count * log(count, 2):
            prev_one = score[1]
            for value in range(2, maximum_value + 1):
                prev_two, prev_one = prev_one, max(prev_one, prev_two + score[value])
        else:
            sorted_keys = sorted(score.keys())
            prev_one = score[sorted_keys[0]]
            for idx in range(1, len(sorted_keys)):
                current_key = sorted_keys[idx]
                if current_key == sorted_keys[idx - 1] + 1:
                    prev_two, prev_one = prev_one, max(prev_one, prev_two + score[current_key])
                else:
                    prev_two, prev_one = prev_one, prev_one + score[current_key]

        return prev_one

In the "Delete and Earn" problem, the implemented function in Python called removeAndAccumulate calculates the maximum points you can earn by deleting numbers from a list, under certain conditions. Here's an overview of how the solution operates:

  • The function initializes a dictionary score to keep a cumulative sum of each integer as a key and its total value as the score you earn for deleting that number. It also maintains a variable maximum_value to track the highest number in the input list.

  • The main logic iterates over the input list numbers, updating score and maximum_value accordingly.

  • Depending on the relationship between maximum_value and a calculated threshold involving the count of unique numbers, the function uses dynamic programming with two approaches:

    • If the maximum value is less than the sum of unique numbers and a logarithmically scaled value of their count, it uses a straightforward dynamic programming iteration over a range from 1 to maximum_value.
    • If greater, the keys of score are sorted, and the function then applies a dynamic programming approach that accounts for whether consecutive numbers are processed, helping avoid sub-optimal point collections when adjacent numbers are hit.
  • To implement this dynamic programming strategy, the solution keeps track of points you could earn by checking two previous states (prev_two and prev_one) which help in deciding whether to skip a number or take it.

  • Finally, the function returns prev_one, which represents the maximum score that can be obtained.

This Python function effectively utilizes dictionaries for efficient scoring and sorting, along with dynamic programming for optimal decision-making based on previous states. This approach ensures that you maximize the points based on deleting numbers according to the given rules.

Comments

No comments yet.