3810. Minimum Operations to Reach Target Array
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 tox. In other words, you locate every run of consecutive positions whose value is exactlyx. - 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.
How We Pick the Algorithm
Why Hash Table / Counting?
This problem maps to Hash Table / Counting through a short path in the full flowchart.
Storing seen values in a hash table provides constant-time lookup and counting.
Open in FlowchartIntuition
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:
-
Iterate over the two arrays in parallel. We pair up
nums[i]andtarget[i]for every indexi. In Python,zip(nums, target)gives us these pairs(x, y)wherex = nums[i]andy = target[i]. -
Filter the mismatched positions. For each pair
(x, y), we only care about it whenx != y, meaning the current value does not yet match the desired value. Positions wherex == yare already correct and are skipped. -
Collect the distinct current values into a set. For every mismatched pair, we insert the current value
xinto a sets. Because a set discards duplicates, all positions sharing the same valuexcollapse into a single entry. This mirrors the fact that one operation on valuexfixes all of them at once. -
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), wherenis the length of the arrays. We make a single pass over both arrays, and each insertion into the hash set takes averageO(1)time. - Space complexity:
O(n)in the worst case, since the set may store up tondistinct 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 i | nums[i] | target[i] | match? | action |
|---|---|---|---|---|
| 0 | 3 | 3 | ✅ equal | skip, already correct |
| 1 | 3 | 8 | ❌ differ | must process value 3 |
| 2 | 7 | 7 | ✅ equal | skip, already correct |
| 3 | 5 | 9 | ❌ differ | must process value 5 |
| 4 | 7 | 2 | ❌ differ | must 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 = 3rewrites index 1 (the only mismatched3) to its target8. → 1 operation - Choosing
x = 5rewrites index 3 to its target9. → 1 operation - Choosing
x = 7rewrites index 4 to its target2. Note index 2 also holds7, but its target is already7, so it harmlessly stays7. → 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
651class 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}
201class 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};
201/**
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}
28Time and Space Complexity
-
Time Complexity:
O(n), wherenis the length of the array. Thezip(nums, target)pairs up corresponding elements, and the set comprehension iterates through allnpairs exactly once. Each comparisonx != yand potential insertion into the set takesO(1)on average, resulting in an overall linear time complexity. The finallen(s)operation runs inO(1). -
Space Complexity:
O(n), wherenis the length of the array. In the worst case, when every element innumsdiffers from its corresponding element intarget, the setswill store up tondistinct values, requiringO(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 RoadmapHow 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
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion If you prefer videos here's a video that explains recursion in a fun and easy way Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask him
Want a Structured Path to Master System Design Too? Don’t Miss This!