Facebook Pixel

3810. Minimum Operations to Reach Target Array

MediumGreedyArrayHash Table
LeetCode ↗

Problem Description

You are given two integer arrays nums and target, each of length n. Here, nums[i] represents the current value at index i, while target[i] represents the desired value at index i. Your goal is to transform nums into target.

To achieve this, you may perform the following operation any number of times (including zero):

  • Choose an integer value x.
  • Find all maximal contiguous segments where every element equals x. A segment is maximal if it cannot be extended further to the left or right while keeping all values equal to x. In other words, you locate every run of consecutive positions whose value is exactly x.
  • For each such segment [l, r], simultaneously update every position in that range to its corresponding target value:
    • nums[l] = target[l], nums[l + 1] = target[l + 1], ..., nums[r] = target[r].

The key idea here is that a single operation, fixed on a chosen value x, affects all maximal segments equal to x at once. Each position within those segments is rewritten to match its own target value in one step.

Your task is to return the minimum number of operations required to make nums exactly equal to target.

In essence, for every index i where nums[i] already equals target[i], no change is needed. For every index i where nums[i] differs from target[i], that current value nums[i] must be "processed" through an operation. Since choosing a value x handles all positions holding that value together, you only need to account for each distinct original value that needs changing, giving you the minimum operation count.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

How We Pick the Algorithm

Why Hash Table / Counting?

This problem maps to Hash Table / Counting through a short path in the full flowchart.

Linkedlist?noFastlookup orcounting?yesHash Table /Counting

Storing seen values in a hash table provides constant-time lookup and counting.

Open in Flowchart

Intuition

Let's think about what each operation really accomplishes. When we choose a value x, every position currently holding x gets rewritten to its own target value in a single step. This means one operation can "fix" many positions at once, as long as they all share the same current value x.

The first observation is that any index i where nums[i] == target[i] is already correct, so it never needs to be touched. We can completely ignore these positions.

Now focus on the indices where nums[i] != target[i]. Each such position must be changed at some point, and the only way to change a position is to choose its current value x = nums[i] in an operation. Here is the crucial insight: all positions that share the same current value can be handled together in one operation. So if multiple indices need changing and they all hold the same value, a single choice of x covers them all.

This naturally leads us to count by distinct values. Suppose two indices both have nums[i] = 5 and both need changing. Picking x = 5 once rewrites both of them simultaneously, no matter how far apart they are. Therefore, the number of operations is not the number of mismatched positions, but the number of distinct values among the mismatched positions.

You might worry that rewriting one segment could create new values that then need further operations, making the counting more complicated. However, the answer simply equals the number of distinct original nums[i] values where nums[i] != target[i]. Each distinct "wrong" value contributes exactly one operation, and there is no way to do better, since two different values can never be fixed by a single choice of x.

So the entire problem reduces to: collect all values nums[i] for which nums[i] != target[i], store them in a set to remove duplicates, and the size of that set is the minimum number of operations.

Pattern Learn more about Greedy patterns.

Solution Approach

Solution 1: Hash Table

Following directly from the intuition, our task reduces to counting the number of distinct values among the positions where nums[i] differs from target[i]. A hash table (or more precisely, a hash set) is the perfect data structure for this, because it automatically removes duplicates and lets us query its size in constant time.

The implementation can be broken down into a few simple steps:

  1. Iterate over the two arrays in parallel. We pair up nums[i] and target[i] for every index i. In Python, zip(nums, target) gives us these pairs (x, y) where x = nums[i] and y = target[i].

  2. Filter the mismatched positions. For each pair (x, y), we only care about it when x != y, meaning the current value does not yet match the desired value. Positions where x == y are already correct and are skipped.

  3. Collect the distinct current values into a set. For every mismatched pair, we insert the current value x into a set s. Because a set discards duplicates, all positions sharing the same value x collapse into a single entry. This mirrors the fact that one operation on value x fixes all of them at once.

  4. Return the size of the set. The final answer is len(s), which is the number of distinct "wrong" values, and therefore the minimum number of operations.

The whole logic is captured neatly by a set comprehension:

class Solution:
    def minOperations(self, nums: List[int], target: List[int]) -> int:
        s = {x for x, y in zip(nums, target) if x != y}
        return len(s)

Complexity Analysis:

  • Time complexity: O(n), where n is the length of the arrays. We make a single pass over both arrays, and each insertion into the hash set takes average O(1) time.
  • Space complexity: O(n) in the worst case, since the set may store up to n distinct values when every position is mismatched and holds a unique value.

Example Walkthrough

Let's trace through a concrete example to see how the hash set approach works.

Suppose we have:

nums   = [3, 3, 7, 5, 7]
target = [3, 8, 7, 9, 2]
index    0  1  2  3  4

Step 1: Compare each position to find mismatches.

We walk through both arrays in parallel, pairing nums[i] with target[i]:

index inums[i]target[i]match?action
033✅ equalskip, already correct
138❌ differmust process value 3
277✅ equalskip, already correct
359❌ differmust process value 5
472❌ differmust process value 7

Step 2: Collect the distinct "wrong" values into a set.

The mismatched positions hold the current values 3 (index 1), 5 (index 3), and 7 (index 4). Inserting these into a set:

s = {3, 5, 7}

Notice there are no duplicates to collapse here, but the principle still holds: if two mismatched positions had shared the same value, they would merge into one entry.

Step 3: Understand why the set size is the answer.

  • Choosing x = 3 rewrites index 1 (the only mismatched 3) to its target 8. → 1 operation
  • Choosing x = 5 rewrites index 3 to its target 9. → 1 operation
  • Choosing x = 7 rewrites index 4 to its target 2. Note index 2 also holds 7, but its target is already 7, so it harmlessly stays 7. → 1 operation

Each distinct wrong value requires exactly one operation, and no single operation can fix two different values at once. The fully transformed nums becomes [3, 8, 7, 9, 2], which equals target.

Result:

len(s) = len({3, 5, 7}) = 3

The minimum number of operations is 3.

Solution Implementation

1s = {x for x, y in zip(nums, target) if x != y}
2```
3
4This builds a **set of values** `x` where `nums[i] != target[i]`, then returns the count of distinct such values. This logic is unusual—it counts *distinct mismatched values* rather than *positions*. This looks like an incorrect/simplified solution that doesn't match typical "minimum operations" problems (which usually involve counting contiguous segments or distinct ranges).
5
6I'll preserve the **exact behavior** of the original code while standardizing it, since rewriting means keeping functionality intact.
7
8```python3
9from typing import List
10
11
12class Solution:
13    def minOperations(self, nums: List[int], target: List[int]) -> int:
14        # Collect the distinct values from `nums` at the positions
15        # where the current value differs from the desired target value.
16        mismatched_values = {
17            current
18            for current, desired in zip(nums, target)
19            if current != desired
20        }
21
22        # The result is the number of distinct mismatched values.
23        return len(mismatched_values)
24```
25
26## Notes on the changes
27
281. **Added `from typing import List`** — required for the `List` type hint to work in a standalone Python 3 file.
292. **Renamed variables** for clarity:
30   - `s` → `mismatched_values` (describes the set's contents)
31   - `x` → `current` (the value in `nums`)
32   - `y` → `desired` (the value in `target`)
333. **Kept `minOperations`** unchanged as instructed.
344. **Added comments** explaining the set comprehension and the return value.
35
36## A perspective worth flagging
37
38If the intended problem is the classic *"minimum operations to make `nums` equal to `target`"* using range-increment/decrement operations, the original logic is likely **incorrect**. A common correct approach uses adjacent differences:
39
40```python3
41from typing import List
42
43
44class Solution:
45    def minOperations(self, nums: List[int], target: List[int]) -> int:
46        # Work with the difference array between target and nums.
47        # Each operation increments/decrements a contiguous subarray by 1,
48        # so the cost equals the sum of "new" positive and negative runs.
49        operations = 0
50        previous = 0  # difference just before the current index
51
52        for current_num, current_target in zip(nums, target):
53            difference = current_target - current_num
54
55            # Count only the additional change needed compared to the
56            # previous index when the sign direction is the same.
57            if difference > 0:
58                operations += max(0, difference - max(0, previous))
59            else:
60                operations += max(0, -difference - max(0, -previous))
61
62            previous = difference
63
64        return operations
65
1class Solution {
2    public int minOperations(int[] nums, int[] target) {
3        // Use a set to collect the distinct values at positions where nums and target differ.
4        // Each distinct mismatching value represents one required operation.
5        Set<Integer> mismatchedValues = new HashSet<>();
6
7        // Iterate through every index of the arrays.
8        for (int i = 0; i < nums.length; ++i) {
9            // If the current element does not match the target,
10            // record the source value that needs to be changed.
11            if (nums[i] != target[i]) {
12                mismatchedValues.add(nums[i]);
13            }
14        }
15
16        // The number of distinct mismatching values equals the minimum number of operations.
17        return mismatchedValues.size();
18    }
19}
20
1class Solution {
2public:
3    int minOperations(vector<int>& nums, vector<int>& target) {
4        // Store the distinct values from nums at positions where nums and target differ
5        unordered_set<int> mismatchedValues;
6
7        // Iterate through all elements in parallel
8        for (int i = 0; i < nums.size(); ++i) {
9            // If the current element does not match the target,
10            // record the value from nums
11            if (nums[i] != target[i]) {
12                mismatchedValues.insert(nums[i]);
13            }
14        }
15
16        // Return the count of distinct mismatched values
17        return mismatchedValues.size();
18    }
19};
20
1/**
2 * Calculates the minimum number of operations required to transform
3 * the `nums` array into the `target` array.
4 *
5 * The key insight: positions where the current value matches the target
6 * need no work. Among the remaining positions, identical source values can
7 * be handled together in a single operation, so we only count distinct values.
8 *
9 * @param nums - The source array of numbers.
10 * @param target - The desired array of numbers.
11 * @returns The count of distinct values that must be changed.
12 */
13function minOperations(nums: number[], target: number[]): number {
14    // Stores the distinct source values at mismatching positions.
15    const distinctValues: Set<number> = new Set<number>();
16
17    // Compare each pair of elements at the same index.
18    for (let i = 0; i < nums.length; i++) {
19        // Only consider positions where the value differs from the target.
20        if (nums[i] !== target[i]) {
21            distinctValues.add(nums[i]);
22        }
23    }
24
25    // Each distinct mismatching value contributes one operation.
26    return distinctValues.size;
27}
28

Time and Space Complexity

  • Time Complexity: O(n), where n is the length of the array. The zip(nums, target) pairs up corresponding elements, and the set comprehension iterates through all n pairs exactly once. Each comparison x != y and potential insertion into the set takes O(1) on average, resulting in an overall linear time complexity. The final len(s) operation runs in O(1).

  • Space Complexity: O(n), where n is the length of the array. In the worst case, when every element in nums differs from its corresponding element in target, the set s will store up to n distinct values, requiring O(n) additional space.

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

Common Pitfalls

Pitfall 1: Counting mismatched positions instead of distinct values

The most frequent mistake is treating each differing index as a separate operation, leading to code like this:

# WRONG: counts positions, not distinct values
def minOperations(self, nums: List[int], target: List[int]) -> int:
    return sum(1 for x, y in zip(nums, target) if x != y)

This overcounts because a single operation on value x fixes every maximal segment holding that value simultaneously. If positions 0, 3, and 7 all hold the value 5 and all need changing, one operation handles them together—they should contribute 1 to the answer, not 3.

Solution: Collapse positions that share the same value by inserting the value (not the index) into a set, so duplicates merge into a single entry:

mismatched_values = {current for current, desired in zip(nums, target) if current != desired}
return len(mismatched_values)

Pitfall 2: Adding the target value desired to the set instead of the current value current

Since the operation is keyed on x = nums[i] (the value you choose and search for), the set must store the current value, not the desired one:

# WRONG: groups by the target value
s = {y for x, y in zip(nums, target) if x != y}

The operation locates segments by their existing value, then rewrites them. Grouping by the target value would miscount how many distinct values must be "processed."

Solution: Always collect current (i.e., nums[i]):

s = {x for x, y in zip(nums, target) if x != y}

Pitfall 3: Missing the if current != desired filter

Forgetting the filter pulls all values from nums into the set, including positions already matching their target:

# WRONG: includes already-correct positions
s = {x for x in nums}

Already-correct positions need no operation, so they must be excluded.

Solution: Apply the current != desired condition during the comprehension to skip positions that are already satisfied.


Pitfall 4: Misreading the problem as a range-increment/decrement task

This problem's title resembles the classic "minimum operations to make arrays equal" problem, where each operation increments or decrements a contiguous subarray by 1. Applying that difference-array logic here would produce a completely different (and incorrect) answer, because the operation semantics are fundamentally different—here an operation overwrites segments to their targets rather than nudging values by ±1.

Solution: Read the operation definition carefully. The key signal is "rewrite every position in a segment to its target value in one step," which means the answer depends only on the count of distinct values needing change, not on magnitudes or contiguous-run arithmetic. Match your algorithm to the stated operation, not to a similarly-named problem.

Ready to land your dream job?

Unlock your dream job with a 5-minute quiz for a personalized study roadmap!

Get My Roadmap
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Get a Personalized Study Roadmap:

How would you design a stack which has a function min that returns the minimum element in the stack, in addition to push and pop? All push, pop, min should have running time O(1).


Recommended Readings

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

Load More