Facebook Pixel

2541. Minimum Operations to Make Array Equal II

Problem Description

You have two integer arrays nums1 and nums2 that are both the same length n, and an integer k.

You can perform the following operation on nums1:

  • Pick any two different indices i and j
  • Add k to nums1[i]
  • Subtract k from nums1[j]

This operation maintains the total sum of nums1 since you're adding k to one element and subtracting k from another.

Your goal is to make nums1 exactly equal to nums2, meaning every element at each index must match: nums1[i] == nums2[i] for all indices from 0 to n-1.

Return the minimum number of operations needed to achieve this. If it's impossible to make the arrays equal, return -1.

For example, if nums1 = [4, 3, 1, 4], nums2 = [1, 3, 7, 1], and k = 3:

  • You could add 3 to nums1[0] and subtract 3 from nums1[2], making nums1 = [7, 3, -2, 4]
  • Then add 3 to nums1[2] twice and subtract 3 from nums1[3] twice, eventually reaching nums1 = [1, 3, 7, 1]

The solution needs to handle edge cases like when k = 0 (no changes possible unless arrays are already equal) and when the differences between corresponding elements aren't divisible by k (making transformation impossible).

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

Intuition

Let's think about what each operation actually does. When we add k to nums1[i] and subtract k from nums1[j], we're essentially transferring k units from position j to position i. The total sum of the array remains unchanged.

For each index i, we need nums1[i] to become nums2[i]. The difference nums1[i] - nums2[i] tells us how much excess or deficit we have at position i. If this difference is positive, we have excess that needs to be removed. If negative, we have a deficit that needs to be filled.

Key observations:

  1. Since each operation transfers exactly k units, any difference nums1[i] - nums2[i] must be divisible by k. If not, it's impossible to fix that position.

  2. The total sum of nums1 never changes through our operations. Therefore, if sum(nums1) != sum(nums2), it's impossible to make them equal.

  3. Every unit of excess at one position must be matched with a unit of deficit at another position. If we have +3k excess at position i, we need exactly -3k deficit somewhere else to balance it out.

  4. To transfer m*k units from position j to position i, we need exactly |m| operations. But here's the clever part: when we count the total operations needed, we're counting each transfer twice - once as removing excess from position j and once as filling deficit at position i. That's why the final answer is total_transfers / 2.

The special case k = 0 means no transfers are possible, so the arrays must already be equal at every position.

Learn more about Greedy and Math patterns.

Solution Approach

The implementation uses a single-pass algorithm to check feasibility and calculate the minimum operations simultaneously.

We maintain two key variables:

  • x: Tracks the cumulative difference between nums1 and nums2. This helps verify if the total sum matches.
  • ans: Accumulates the total absolute differences, which represents the total amount of transfers needed.

Algorithm Steps:

  1. Iterate through both arrays simultaneously using zip(nums1, nums2) to process corresponding elements.

  2. Handle the special case k = 0:

    • If k = 0, no transfers are possible
    • If a != b at any position, return -1 immediately
    • Otherwise, continue to the next position
  3. Check divisibility for each difference:

    • Calculate (a - b) for current position
    • If (a - b) % k != 0, the difference cannot be resolved with transfers of size k, so return -1
  4. Track the transfers:

    • Calculate y = (a - b) // k, which represents how many transfers of size k are needed
    • Add abs(y) to ans to count the total transfer amount
    • Add y (with sign) to x to track the net difference
  5. Final validation:

    • After processing all positions, check if x == 0
    • If x != 0, the sums don't match, making transformation impossible, so return -1
    • Otherwise, return ans // 2

Why ans // 2? Each transfer involves two positions - one giving and one receiving. When we sum up abs(y) for all positions, we count each transfer twice: once as a positive difference (excess) and once as a negative difference (deficit). Therefore, the actual number of operations is half of the total absolute differences.

Time Complexity: O(n) where n is the length of the arrays Space Complexity: O(1) as we only use a constant amount of extra space

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 concrete example to illustrate the solution approach.

Example: nums1 = [3, 8, 5, 2], nums2 = [7, 2, 3, 6], k = 2

Step 1: Calculate differences at each position

  • Position 0: 3 - 7 = -4 (need to add 4)
  • Position 1: 8 - 2 = 6 (need to remove 6)
  • Position 2: 5 - 3 = 2 (need to remove 2)
  • Position 3: 2 - 6 = -4 (need to add 4)

Step 2: Check feasibility

  • All differences (-4, 6, 2, -4) are divisible by k = 2
  • Sum of differences: -4 + 6 + 2 + (-4) = 0
  • Total sum check: sum(nums1) = 18, sum(nums2) = 18

Step 3: Calculate transfers needed

  • Position 0: -4 ÷ 2 = -2 transfers (needs 2 incoming transfers)
  • Position 1: 6 ÷ 2 = 3 transfers (needs 3 outgoing transfers)
  • Position 2: 2 ÷ 2 = 1 transfer (needs 1 outgoing transfer)
  • Position 3: -4 ÷ 2 = -2 transfers (needs 2 incoming transfers)

Step 4: Count total transfer amount

  • Total absolute transfers: |-2| + |3| + |1| + |-2| = 2 + 3 + 1 + 2 = 8

Step 5: Calculate operations

  • Since each operation moves k units from one position to another, and we counted each transfer twice (once as outgoing, once as incoming), the answer is 8 ÷ 2 = 4 operations.

Verification of the operations:

  1. Transfer from position 1 to position 0: nums1 = [5, 6, 5, 2]
  2. Transfer from position 1 to position 0: nums1 = [7, 4, 5, 2]
  3. Transfer from position 1 to position 3: nums1 = [7, 2, 5, 4]
  4. Transfer from position 2 to position 3: nums1 = [7, 2, 3, 6]

After 4 operations, nums1 equals nums2!

Solution Implementation

1class Solution:
2    def minOperations(self, nums1: List[int], nums2: List[int], k: int) -> int:
3        # Initialize total operations counter and net change tracker
4        total_operations = 0
5        net_change = 0
6      
7        # Iterate through both arrays simultaneously
8        for num1_val, num2_val in zip(nums1, nums2):
9            # Special case: when k is 0, arrays must be identical
10            if k == 0:
11                if num1_val != num2_val:
12                    return -1
13                continue
14          
15            # Check if the difference is divisible by k
16            if (num1_val - num2_val) % k != 0:
17                return -1
18          
19            # Calculate the number of k-operations needed for this index
20            operations_at_index = (num1_val - num2_val) // k
21          
22            # Add absolute value to total operations count
23            total_operations += abs(operations_at_index)
24          
25            # Track net change (positive operations vs negative operations)
26            net_change += operations_at_index
27      
28        # If net change is not zero, operations don't balance out
29        if net_change != 0:
30            return -1
31      
32        # Each operation affects two indices, so divide by 2
33        return total_operations // 2
34
1class Solution {
2    public long minOperations(int[] nums1, int[] nums2, int k) {
3        // Total number of operations needed (counting both additions and subtractions)
4        long totalOperations = 0;
5        // Net difference tracker to ensure balance between additions and subtractions
6        long netDifference = 0;
7      
8        // Iterate through both arrays simultaneously
9        for (int i = 0; i < nums1.length; i++) {
10            int currentNum1 = nums1[i];
11            int currentNum2 = nums2[i];
12          
13            // Special case: when k is 0, no operations are possible
14            if (k == 0) {
15                // If elements differ when k=0, transformation is impossible
16                if (currentNum1 != currentNum2) {
17                    return -1;
18                }
19                // Elements are equal, continue to next pair
20                continue;
21            }
22          
23            // Check if the difference between elements is divisible by k
24            // If not, we cannot transform currentNum1 to currentNum2
25            if ((currentNum1 - currentNum2) % k != 0) {
26                return -1;
27            }
28          
29            // Calculate the number of operations needed for this position
30            // Positive means we need to subtract from nums1[i]
31            // Negative means we need to add to nums1[i]
32            int operationCount = (currentNum1 - currentNum2) / k;
33          
34            // Add absolute value to total operations
35            totalOperations += Math.abs(operationCount);
36          
37            // Track net difference to ensure conservation
38            // Sum should be 0 for valid transformation
39            netDifference += operationCount;
40        }
41      
42        // Check if the operations balance out (what we add equals what we subtract)
43        // If balanced, return half of total operations (since each operation affects two elements)
44        // Otherwise, transformation is impossible
45        return netDifference == 0 ? totalOperations / 2 : -1;
46    }
47}
48
1class Solution {
2public:
3    long long minOperations(vector<int>& nums1, vector<int>& nums2, int k) {
4        long long totalOperations = 0;  // Total number of operations needed
5        long long netDifference = 0;     // Net difference to check balance
6      
7        // Iterate through both arrays simultaneously
8        for (int i = 0; i < nums1.size(); ++i) {
9            int currentNum1 = nums1[i];
10            int currentNum2 = nums2[i];
11          
12            // Special case: when k is 0, arrays must already be identical
13            if (k == 0) {
14                if (currentNum1 != currentNum2) {
15                    return -1;  // Cannot make arrays equal without operations
16                }
17                continue;
18            }
19          
20            // Check if the difference is divisible by k
21            int difference = currentNum1 - currentNum2;
22            if (difference % k != 0) {
23                return -1;  // Cannot make elements equal with operations of size k
24            }
25          
26            // Calculate number of operations needed for this pair
27            int operationsForPair = difference / k;
28          
29            // Accumulate absolute value (each operation counts)
30            totalOperations += abs(operationsForPair);
31          
32            // Track net difference (positive and negative should balance)
33            netDifference += operationsForPair;
34        }
35      
36        // Check if operations balance out (sum of differences should be 0)
37        // If balanced, return half of total operations (each operation affects 2 elements)
38        return (netDifference == 0) ? totalOperations / 2 : -1;
39    }
40};
41
1/**
2 * Calculates the minimum number of operations to transform nums1 into nums2
3 * by adding/subtracting k from elements
4 * @param nums1 - First array of numbers
5 * @param nums2 - Second array of numbers (target)
6 * @param k - The value to add or subtract in each operation
7 * @returns Minimum number of operations, or -1 if impossible
8 */
9function minOperations(nums1: number[], nums2: number[], k: number): number {
10    const arrayLength: number = nums1.length;
11  
12    // Special case: when k is 0, arrays must be identical
13    if (k === 0) {
14        const areArraysIdentical: boolean = nums1.every((value, index) => value === nums2[index]);
15        return areArraysIdentical ? 0 : -1;
16    }
17  
18    // Track the total difference and absolute difference
19    let totalDifference: number = 0;
20    let totalAbsoluteDifference: number = 0;
21  
22    // Process each element pair
23    for (let i = 0; i < arrayLength; i++) {
24        const difference: number = nums1[i] - nums2[i];
25      
26        // Accumulate the signed difference
27        totalDifference += difference;
28      
29        // Check if the difference is divisible by k
30        if (difference % k !== 0) {
31            return -1; // Impossible to transform if not divisible by k
32        }
33      
34        // Accumulate the absolute difference
35        totalAbsoluteDifference += Math.abs(difference);
36    }
37  
38    // The total difference must be zero for a valid transformation
39    if (totalDifference !== 0) {
40        return -1;
41    }
42  
43    // Each operation affects two elements, so divide by 2k
44    return totalAbsoluteDifference / (k * 2);
45}
46

Time and Space Complexity

The time complexity of this solution is O(n), where n is the length of the arrays nums1 and nums2. This is because the algorithm iterates through both arrays exactly once using zip(nums1, nums2), performing constant-time operations for each pair of elements (arithmetic operations, modulo checks, and variable updates).

The space complexity is O(1) as the algorithm only uses a fixed amount of extra space regardless of the input size. The variables ans, x, a, b, and y are the only additional storage used, and their space requirements don't scale with the input size n.

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

Common Pitfalls

1. Forgetting to Handle the k = 0 Special Case

Pitfall: When k = 0, no operations are possible since adding/subtracting 0 doesn't change any values. Many solutions forget this edge case and might attempt division by zero or return incorrect results.

Example of incorrect handling:

# WRONG - This will cause ZeroDivisionError
operations_at_index = (num1_val - num2_val) // k  # Crashes when k = 0

Solution: Always check for k = 0 first and handle it separately:

if k == 0:
    if num1_val != num2_val:
        return -1  # Can't make arrays equal
    continue  # Skip to next element if already equal

2. Not Checking if the Sum of Arrays Match

Pitfall: Since each operation adds k to one element and subtracts k from another, the total sum of nums1 must equal the total sum of nums2 for transformation to be possible. Failing to verify this leads to incorrect results.

Example scenario that would fail without sum checking:

  • nums1 = [1, 2, 3], nums2 = [2, 3, 5], k = 1
  • Sum of nums1 = 6, Sum of nums2 = 10
  • Without the net_change check, the algorithm might not detect this impossibility

Solution: Track the net change throughout the iteration and verify it equals zero at the end:

net_change += operations_at_index
# After loop
if net_change != 0:
    return -1

3. Forgetting to Divide the Total Operations by 2

Pitfall: Each operation involves two indices - one gains k and one loses k. When summing absolute differences, each operation gets counted twice (once as positive difference, once as negative).

Example of the double-counting issue:

  • nums1 = [5, 3], nums2 = [3, 5], k = 2
  • Index 0 needs -1 operation (subtract 2), Index 1 needs +1 operation (add 2)
  • Total absolute differences = |−1| + |1| = 2
  • But this represents just ONE operation (moving 2 from index 0 to index 1)

Solution: Always divide the final count by 2:

return total_operations // 2  # Not just total_operations

4. Using Modulo Check Incorrectly with Negative Numbers

Pitfall: In Python, modulo with negative numbers works correctly, but conceptually some might check divisibility incorrectly or use absolute values unnecessarily.

Incorrect approach:

# WRONG - Using absolute value loses important sign information
if abs(num1_val - num2_val) % k != 0:
    return -1
operations = abs(num1_val - num2_val) // k  # Lost direction of transfer

Solution: Keep the sign information intact:

if (num1_val - num2_val) % k != 0:
    return -1
operations_at_index = (num1_val - num2_val) // k  # Preserves sign for net_change tracking
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

A person thinks of a number between 1 and 1000. You may ask any number questions to them, provided that the question can be answered with either "yes" or "no".

What is the minimum number of questions you needed to ask so that you are guaranteed to know the number that the person is thinking?


Recommended Readings

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

Load More