Facebook Pixel

2357. Make Array Zero by Subtracting Equal Amounts

Problem Description

You have an array nums containing non-negative integers. You need to reduce all elements to 0 using a specific type of operation.

In each operation, you must:

  1. Pick a positive integer x where x cannot be larger than the smallest non-zero element currently in nums
  2. Subtract x from every positive element in nums (elements that are 0 remain unchanged)

Your goal is to find the minimum number of operations needed to make all elements in nums equal to 0.

The key insight is that when you perform an operation, you can choose x to be exactly equal to the smallest non-zero element. This will reduce that smallest element (and all other elements with the same value) to 0 in one operation. Elements larger than x will be reduced but remain positive.

Since we can eliminate all occurrences of the smallest non-zero value in each operation, the minimum number of operations equals the number of distinct non-zero values in the array. This is why the solution simply counts unique non-zero elements using len({x for x in nums if x}) - it creates a set of all non-zero values and returns its size.

For example, if nums = [1, 5, 0, 3, 5]:

  • Distinct non-zero values are {1, 3, 5}
  • We need 3 operations:
    • Operation 1: Choose x = 1, array becomes [0, 4, 0, 2, 4]
    • Operation 2: Choose x = 2, array becomes [0, 2, 0, 0, 2]
    • Operation 3: Choose x = 2, array becomes [0, 0, 0, 0, 0]
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

Let's think about what happens during each operation. When we choose a value x and subtract it from all positive elements, we're essentially "shifting down" all positive values by the same amount.

The crucial observation is that if we always choose x to be the smallest non-zero element in the array, we accomplish something important: we eliminate that value entirely from the array (along with all duplicates of that value). Why? Because subtracting the smallest non-zero value from itself gives 0, and subtracting it from any duplicate also gives 0.

Consider what happens step by step:

  • In the first operation, we eliminate the smallest non-zero value
  • In the second operation, we eliminate what becomes the new smallest non-zero value
  • This continues until all values reach 0

Since we can eliminate one unique value per operation (along with all its duplicates), and we need to eliminate all unique non-zero values to make the entire array 0, the minimum number of operations is exactly equal to the count of distinct non-zero values.

This transforms our problem from "how many operations do we need?" to simply "how many different non-zero values exist in the array?". The duplicates don't matter because they get eliminated together in the same operation.

That's why the solution is elegantly simple: len({x for x in nums if x}). We create a set of all non-zero elements (which automatically removes duplicates) and count its size. This count directly gives us the minimum number of operations needed.

Learn more about Greedy, Sorting and Heap (Priority Queue) patterns.

Solution Approach

The solution uses a hash table (implemented as a Python set) to count the number of distinct non-zero elements in the array. This approach is both elegant and efficient.

Implementation Steps:

  1. Create a set of non-zero elements: The expression {x for x in nums if x} creates a set comprehension that:

    • Iterates through each element x in nums
    • Filters out zeros using the condition if x (since 0 evaluates to False in Python)
    • Automatically removes duplicates (property of sets)
  2. Count the distinct elements: The len() function returns the size of the set, which represents the number of unique non-zero values.

Why this works:

  • Each operation can eliminate all occurrences of one unique value from the array
  • We need exactly as many operations as there are unique non-zero values
  • The set data structure naturally handles the uniqueness requirement

Time and Space Complexity:

  • Time Complexity: O(n) where n is the length of the array, as we iterate through the array once
  • Space Complexity: O(k) where k is the number of distinct non-zero elements in the array (at most n)

Alternative Implementation: You could also use an array or explicit hash table to count distinct elements, but the set approach is the most concise and Pythonic way to solve this problem.

Example walkthrough with nums = [1, 5, 0, 3, 5]:

  • Set comprehension creates: {1, 3, 5} (the 0 is filtered out, duplicate 5 is removed)
  • len({1, 3, 5}) returns 3
  • Therefore, minimum operations needed = 3

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a detailed example with nums = [2, 2, 3, 1, 1, 0].

Step 1: Identify distinct non-zero values

  • Looking at our array: [2, 2, 3, 1, 1, 0]
  • Non-zero elements: 2, 2, 3, 1, 1
  • Distinct non-zero values: {1, 2, 3}
  • Count = 3, so we'll need 3 operations

Step 2: Simulate the operations

Operation 1:

  • Current array: [2, 2, 3, 1, 1, 0]
  • Smallest non-zero element: 1
  • Choose x = 1
  • Subtract 1 from all positive elements:
    • 2 - 1 = 1
    • 2 - 1 = 1
    • 3 - 1 = 2
    • 1 - 1 = 0
    • 1 - 1 = 0
    • 0 stays 0
  • Result: [1, 1, 2, 0, 0, 0]

Operation 2:

  • Current array: [1, 1, 2, 0, 0, 0]
  • Smallest non-zero element: 1
  • Choose x = 1
  • Subtract 1 from all positive elements:
    • 1 - 1 = 0
    • 1 - 1 = 0
    • 2 - 1 = 1
    • Zeros remain unchanged
  • Result: [0, 0, 1, 0, 0, 0]

Operation 3:

  • Current array: [0, 0, 1, 0, 0, 0]
  • Smallest non-zero element: 1
  • Choose x = 1
  • Subtract 1 from all positive elements:
    • Only the 1 becomes 0
    • All other elements are already 0
  • Result: [0, 0, 0, 0, 0, 0]

Step 3: Verify with our solution

  • Using the set comprehension: {x for x in nums if x}
  • This creates: {2, 3, 1} (zeros filtered out, duplicates removed)
  • len({2, 3, 1}) = 3
  • Matches our simulation: 3 operations needed ✓

The key insight: We eliminated exactly one distinct value per operation (first all 1s, then the remaining 1s that came from 2s, then the final 1 that came from 3). This confirms that counting distinct non-zero values gives us the minimum operations needed.

Solution Implementation

1class Solution:
2    def minimumOperations(self, nums: List[int]) -> int:
3        # Create a set of unique non-zero elements from the input array
4        # The set comprehension filters out zeros (x for x in nums if x)
5        # since 'if x' evaluates to False when x is 0
6        unique_non_zero_elements = {x for x in nums if x}
7      
8        # The minimum number of operations needed is equal to 
9        # the count of unique non-zero values in the array
10        # Each operation reduces all instances of the smallest positive value to 0
11        return len(unique_non_zero_elements)
12
1class Solution {
2    public int minimumOperations(int[] nums) {
3        // Boolean array to track which values have been encountered
4        // Index represents the value (0-100), true means the value has been seen
5        boolean[] seen = new boolean[101];
6      
7        // Mark 0 as already seen (we don't count zeros as distinct values)
8        seen[0] = true;
9      
10        // Counter for distinct non-zero values
11        int distinctCount = 0;
12      
13        // Iterate through all numbers in the input array
14        for (int num : nums) {
15            // If this value hasn't been seen before
16            if (!seen[num]) {
17                // Increment the count of distinct values
18                distinctCount++;
19                // Mark this value as seen
20                seen[num] = true;
21            }
22        }
23      
24        // Return the total count of distinct non-zero values
25        return distinctCount;
26    }
27}
28
1class Solution {
2public:
3    int minimumOperations(vector<int>& nums) {
4        // Boolean array to track which values have been seen
5        // Index represents the value (0-100), value represents if it's been seen
6        bool seen[101]{};
7      
8        // Mark 0 as already seen (since we don't need to operate on zeros)
9        seen[0] = true;
10      
11        // Counter for minimum operations needed
12        int operationCount = 0;
13      
14        // Iterate through each element in the input array
15        for (int& num : nums) {
16            // If this value hasn't been seen before
17            if (!seen[num]) {
18                // Increment the operation count (we need one operation for each unique non-zero value)
19                ++operationCount;
20                // Mark this value as seen
21                seen[num] = true;
22            }
23        }
24      
25        // Return the total number of operations needed
26        return operationCount;
27    }
28};
29
1/**
2 * Calculates the minimum number of operations needed to make all elements zero.
3 * Each operation allows selecting a positive element and subtracting it from all elements.
4 * 
5 * The solution leverages the fact that the minimum operations equals the number of unique positive values.
6 * Each unique positive value requires exactly one operation to reduce to zero.
7 * 
8 * @param nums - Array of non-negative integers
9 * @returns The minimum number of operations required
10 */
11function minimumOperations(nums: number[]): number {
12    // Create a set to store unique values from the array
13    const uniqueValues: Set<number> = new Set(nums);
14  
15    // Remove zero from the set since zeros don't require any operations
16    uniqueValues.delete(0);
17  
18    // The number of remaining unique positive values is the minimum operations needed
19    return uniqueValues.size;
20}
21

Time and Space Complexity

The time complexity is O(n), where n is the length of the array nums. This is because the code iterates through all elements in nums once to create a set comprehension, checking each element with the condition if x (which filters out zero values).

The space complexity is O(n) in the worst case, where n is the length of the array nums. This occurs when all elements in nums are non-zero and unique, resulting in a set that contains up to n elements. The set comprehension {x for x in nums if x} creates a new set to store the unique non-zero values from the input array.

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

Common Pitfalls

Pitfall 1: Trying to Simulate the Operations

Many people initially attempt to simulate the actual operations by repeatedly finding the minimum non-zero element and subtracting it from all positive elements:

Incorrect Approach:

def minimumOperations(self, nums: List[int]) -> int:
    operations = 0
    while any(nums):  # While there are non-zero elements
        min_val = min(x for x in nums if x > 0)
        nums = [x - min_val if x > 0 else 0 for x in nums]
        operations += 1
    return operations

Issues:

  • Time complexity becomes O(n²) or worse
  • Unnecessarily complex and inefficient
  • Modifies the array multiple times

Solution: Recognize that you don't need to perform the actual operations. The answer depends only on counting distinct non-zero values.

Pitfall 2: Forgetting to Filter Out Zeros

A common mistake is counting all distinct values including zero:

Incorrect Code:

def minimumOperations(self, nums: List[int]) -> int:
    return len(set(nums))  # Wrong! This counts 0 as a distinct value

Why it's wrong: If nums = [1, 0, 3], this returns 3 instead of 2, because it counts {0, 1, 3} instead of {1, 3}.

Solution: Always filter out zeros before counting: len({x for x in nums if x}) or len(set(nums) - {0})

Pitfall 3: Overthinking the Value of x

Some may think they need to optimize the choice of x in each operation or consider different strategies for selecting x.

Misconception: "Maybe choosing a different value of x (not the minimum) could reduce operations"

Clarification: The optimal strategy is always to choose x equal to the smallest non-zero element. Any other choice would leave that smallest element positive, requiring an additional operation later.

Pitfall 4: Using Complex Data Structures

Some might use unnecessary data structures like Counter or sorted lists:

Overcomplicated:

from collections import Counter
def minimumOperations(self, nums: List[int]) -> int:
    counter = Counter(nums)
    if 0 in counter:
        del counter[0]
    return len(counter)

Solution: A simple set comprehension is sufficient and more elegant: {x for x in nums if x}

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

A heap is a ...?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More