Facebook Pixel

453. Minimum Moves to Equal Array Elements

Problem Description

You are given an integer array nums of size n. Your goal is to make all elements in the array equal using the minimum number of moves.

In each move, you can increment exactly n - 1 elements of the array by 1. This means in each operation, you select one element to keep unchanged while increasing all other elements by 1.

For example, if you have nums = [1, 2, 3]:

  • One move could change it to [2, 3, 3] (keeping the last element unchanged)
  • Another move could change it to [2, 2, 4] (keeping the first element unchanged)

The problem asks you to find the minimum number of such moves needed to make all array elements equal.

The key insight is that incrementing n - 1 elements by 1 is mathematically equivalent to decrementing one element by 1 relative to all others. So instead of thinking about raising n - 1 elements, you can think about it as bringing all elements down to the minimum value.

The solution uses a mathematical approach: if the minimum value is mi, the sum of all elements is s, and there are n elements, then after k moves:

  • The total sum increases by k * (n - 1)
  • All elements will equal some final value x
  • The minimum element needs k increments to reach x, so x = mi + k

Setting up the equation s + k * (n - 1) = n * x and substituting x = mi + k, we can solve for k:

  • s + k * (n - 1) = n * (mi + k)
  • s + k * (n - 1) = n * mi + n * k
  • k = s - n * mi

Therefore, the minimum number of moves is sum(nums) - min(nums) * len(nums).

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

Intuition

The key realization is that incrementing n - 1 elements by 1 is equivalent to decrementing 1 element by 1 relative to all others. This perspective shift makes the problem much clearer.

Think about it this way: if we increment all elements except one, we're essentially leaving that one element behind. After many such operations, the element that gets left behind the most will determine our final equal value.

Since we want to minimize the number of moves, we should aim for the smallest possible final value that all elements can reach. The minimum element in the array provides this lower bound - it can never decrease (since we only increment elements), so all elements must eventually reach at least this value.

But wait - the minimum element itself will also be incremented in moves where it's not the one being left behind. After k moves, the minimum element will have been incremented exactly k times (since it's included in the n - 1 elements that get incremented each time). This means the final equal value must be min(nums) + k.

Now we can set up our equation. After k moves:

  • Total sum increases by k * (n - 1) (each move adds n - 1 to the total)
  • Final sum equals n * (min(nums) + k) (n elements, each with value min(nums) + k)

From sum(nums) + k * (n - 1) = n * (min(nums) + k), we can solve for k:

  • sum(nums) + k * n - k = n * min(nums) + n * k
  • sum(nums) - k = n * min(nums)
  • k = sum(nums) - n * min(nums)

This elegant formula tells us that the minimum moves needed is simply the current sum minus what the sum would be if all elements were already at the minimum value.

Solution Approach

The implementation follows directly from the mathematical derivation. We need to calculate k = sum(nums) - n * min(nums), where:

  • sum(nums) is the total sum of all elements in the array
  • min(nums) is the minimum value in the array
  • n is the length of the array

Let's trace through the mathematical reasoning:

  1. Define variables: Let mi be the minimum value, s be the sum of the array, and n be the array length. After k moves, all elements will equal some value x.

  2. Set up equations: After k operations:

    • The total sum becomes: s + (n - 1) * k (original sum plus the increments)
    • This must equal: n * x (n elements, each with value x)
    • So: s + (n - 1) * k = n * x
  3. Find the relationship: Since the minimum element gets incremented in every move, after k moves it becomes:

    • x = mi + k
  4. Substitute and solve: Replace x in our first equation:

    s + (n - 1) * k = n * (mi + k)
    s + (n - 1) * k = n * mi + n * k
    s + n * k - k = n * mi + n * k
    s - k = n * mi
    k = s - n * mi

The Python implementation is remarkably concise:

class Solution:
    def minMoves(self, nums: List[int]) -> int:
        return sum(nums) - min(nums) * len(nums)

This single line computes:

  • sum(nums): Gets the total sum s
  • min(nums): Finds the minimum value mi
  • len(nums): Gets the array length n
  • Returns s - mi * n, which is our answer k

The time complexity is O(n) for finding both the sum and minimum in a single pass through the array. The space complexity is O(1) as we only use constant 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 with nums = [1, 2, 3].

Step 1: Identify what we need

  • Sum of array: s = 1 + 2 + 3 = 6
  • Minimum value: mi = 1
  • Array length: n = 3

Step 2: Apply the formula Using k = s - n * mi:

  • k = 6 - 3 * 1 = 6 - 3 = 3

So we need 3 moves to make all elements equal.

Step 3: Verify with actual moves Let's trace through what happens with 3 moves:

Initial state: [1, 2, 3]

Move 1: Keep element at index 2 unchanged, increment others by 1

  • [1+1, 2+1, 3] = [2, 3, 3]

Move 2: Keep element at index 2 unchanged, increment others by 1

  • [2+1, 3+1, 3] = [3, 4, 3]

Move 3: Keep element at index 1 unchanged, increment others by 1

  • [3+1, 4, 3+1] = [4, 4, 4]

All elements are now equal to 4!

Step 4: Validate the math

  • Final value x = mi + k = 1 + 3 = 4
  • Total sum after moves: s + (n-1) * k = 6 + 2 * 3 = 12
  • Expected sum with all elements at 4: n * x = 3 * 4 = 12

The formula correctly predicted we need 3 moves, and all elements end up equal to 4, which matches our manual simulation perfectly.

Solution Implementation

1class Solution:
2    def minMoves(self, nums: List[int]) -> int:
3        """
4        Calculate minimum number of moves to make all array elements equal.
5      
6        In each move, we can increment n-1 elements by 1.
7        This is mathematically equivalent to decrementing 1 element by 1.
8      
9        The minimum number of moves equals the sum of differences between 
10        each element and the minimum element.
11      
12        Formula: sum(nums) - min(nums) * len(nums)
13      
14        Args:
15            nums: List of integers
16          
17        Returns:
18            Minimum number of moves required
19        """
20        # Find the minimum value in the array
21        min_value = min(nums)
22      
23        # Calculate total sum of all elements
24        total_sum = sum(nums)
25      
26        # The number of moves equals the total difference from minimum
27        # This is equivalent to: sum of (each element - min_value)
28        return total_sum - min_value * len(nums)
29
1class Solution {
2    public int minMoves(int[] nums) {
3        // Calculate the sum of all elements in the array
4        int sum = Arrays.stream(nums).sum();
5      
6        // Find the minimum element in the array
7        int minValue = Arrays.stream(nums).min().getAsInt();
8      
9        // The minimum number of moves equals:
10        // (sum of all elements) - (minimum element * array length)
11        // This works because incrementing n-1 elements is equivalent to
12        // decrementing 1 element. To make all elements equal, we need to
13        // bring all elements down to the minimum value.
14        int minMoves = sum - minValue * nums.length;
15      
16        return minMoves;
17    }
18}
19
1class Solution {
2public:
3    int minMoves(vector<int>& nums) {
4        // Calculate the sum of all elements and find the minimum element
5        int sum = 0;
6        int minValue = INT_MAX;  // Initialize with maximum integer value
7      
8        // Iterate through all numbers to find sum and minimum
9        for (int num : nums) {
10            sum += num;
11            minValue = min(minValue, num);
12        }
13      
14        // The minimum moves needed is the difference between:
15        // - current sum of all elements
16        // - sum if all elements were equal to the minimum value
17        // This equals: sum - (minValue * n)
18        return sum - minValue * nums.size();
19    }
20};
21
1/**
2 * Calculates the minimum number of moves to make all array elements equal.
3 * The strategy is to increment n-1 elements by 1 in each move, which is equivalent
4 * to decrementing one element by 1. The minimum moves needed is the sum of differences
5 * between each element and the minimum element.
6 * 
7 * @param nums - The input array of numbers
8 * @returns The minimum number of moves required
9 */
10function minMoves(nums: number[]): number {
11    // Initialize minimum value to a large number (2^30)
12    let minValue: number = 1 << 30;
13  
14    // Initialize sum of all elements
15    let sum: number = 0;
16  
17    // Iterate through the array to find minimum value and calculate sum
18    for (const num of nums) {
19        sum += num;
20        minValue = Math.min(minValue, num);
21    }
22  
23    // Calculate minimum moves: sum - (minimum value * array length)
24    // This formula works because we need to bring all elements down to the minimum value
25    return sum - minValue * nums.length;
26}
27

Time and Space Complexity

The time complexity is O(n), where n is the length of the array nums. This is because:

  • sum(nums) iterates through all n elements once to calculate the sum, which takes O(n) time
  • min(nums) iterates through all n elements once to find the minimum value, which takes O(n) time
  • len(nums) returns the length in O(1) time
  • The arithmetic operations (subtraction and multiplication) take O(1) time
  • Overall: O(n) + O(n) + O(1) + O(1) = O(n)

The space complexity is O(1) as the algorithm only uses a constant amount of extra space regardless of the input size. The sum() and min() functions use internal variables to track the running sum and minimum value respectively, but these are constant space operations that don't scale with input size.

Common Pitfalls

1. Misunderstanding the Problem Statement

Many people initially think they need to track which elements to increment in each move or simulate the actual moves. This leads to overly complex solutions with higher time complexity.

Wrong Approach:

def minMoves(nums):
    moves = 0
    while len(set(nums)) > 1:  # While not all equal
        nums.sort()
        for i in range(len(nums) - 1):
            nums[i] += 1
        moves += 1
    return moves

Why it's wrong: This simulation approach has O(k*n log n) time complexity where k is the number of moves, which can be very large.

Solution: Recognize that incrementing n-1 elements is equivalent to decrementing 1 element relative to others. Focus on the mathematical relationship rather than simulating moves.

2. Integer Overflow in Other Languages

When implementing in languages like Java or C++, the calculation sum(nums) - min(nums) * len(nums) can cause integer overflow for large arrays with large values.

Problematic Code (Java):

public int minMoves(int[] nums) {
    int sum = 0;
    int min = Integer.MAX_VALUE;
    for (int num : nums) {
        sum += num;  // Can overflow!
        min = Math.min(min, num);
    }
    return sum - min * nums.length;
}

Solution: Use long data type or calculate the sum of differences directly:

public int minMoves(int[] nums) {
    int min = Integer.MAX_VALUE;
    for (int num : nums) {
        min = Math.min(min, num);
    }
    int moves = 0;
    for (int num : nums) {
        moves += (num - min);  // Avoids large intermediate sums
    }
    return moves;
}

3. Attempting to Find the Target Value

Some solutions try to determine what the final equal value will be, which adds unnecessary complexity.

Overcomplicated Approach:

def minMoves(nums):
    min_val = min(nums)
    max_val = max(nums)
    # Try to figure out the target value
    target = min_val + (max_val - min_val)  # Wrong!
    # ... complex logic follows

Solution: You don't need to know the final value. The formula sum(nums) - min(nums) * len(nums) directly gives the answer without needing to determine the target.

4. Edge Case Handling

Forgetting to handle edge cases like single-element arrays or arrays where all elements are already equal.

Incomplete Solution:

def minMoves(nums):
    # Missing edge case check
    return sum(nums) - min(nums) * len(nums)

Better Solution:

def minMoves(nums):
    if len(nums) <= 1:
        return 0
    if len(set(nums)) == 1:  # All elements already equal
        return 0
    return sum(nums) - min(nums) * len(nums)

Note: The formula naturally handles these cases (returns 0), but explicit checks can improve code clarity and prevent unnecessary computation.

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

Which of these pictures shows the visit order of a depth-first search?


Recommended Readings

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

Load More