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 reachx
, sox = 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)
.
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 addsn - 1
to the total) - Final sum equals
n * (min(nums) + k)
(n elements, each with valuemin(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 arraymin(nums)
is the minimum value in the arrayn
is the length of the array
Let's trace through the mathematical reasoning:
-
Define variables: Let
mi
be the minimum value,s
be the sum of the array, andn
be the array length. Afterk
moves, all elements will equal some valuex
. -
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
- The total sum becomes:
-
Find the relationship: Since the minimum element gets incremented in every move, after
k
moves it becomes:x = mi + k
-
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 sums
min(nums)
: Finds the minimum valuemi
len(nums)
: Gets the array lengthn
- Returns
s - mi * n
, which is our answerk
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 EvaluatorExample 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 alln
elements once to calculate the sum, which takesO(n)
timemin(nums)
iterates through alln
elements once to find the minimum value, which takesO(n)
timelen(nums)
returns the length inO(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.
Which of these pictures shows the visit order of a depth-first search?
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
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 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
Want a Structured Path to Master System Design Too? Don’t Miss This!