Minimum Moves to Equal Array Elements: The Decrement Trick
Minimum Moves to Equal Array Elements is LeetCode 453. Given an integer array nums of size n, in one move you can increment n - 1 elements by 1. Return the minimum number of moves required to make all array elements equal.
For example, given [1, 2, 3], the answer is 3. One possible sequence: [1, 2, 3] becomes [2, 3, 3], then [3, 4, 3], then [4, 4, 4]. Three moves total.
At first glance this seems like a simulation problem. You might try to figure out which elements to increment at each step. But that approach is slow and misses the elegant math underneath.
Why this problem matters
This is a pure math insight problem. There is no clever data structure and no tricky algorithm. The entire solution comes down to seeing one equivalence. Problems like this train you to reframe operations before writing any code. That skill transfers to harder problems where brute force is too slow and the path forward is always some mathematical restatement.
The key insight
Here is the trick that unlocks the entire problem: incrementing n - 1 elements by 1 is the same as decrementing 1 element by 1.
Why? Because relative differences are all that matter. If you add 1 to every element except one, the gap between that one element and the rest grows by 1, which is exactly what happens if you subtract 1 from just that element. The absolute values differ, but the number of moves to equalize stays the same.
Once you see this equivalence, the problem becomes: how many times do you need to decrement individual elements to make them all equal? The answer is obvious. You want to bring every element down to the minimum. For each element, the cost is nums[i] - min(nums). Sum those up and you have the answer.
That sum simplifies to:
sum(nums) - n * min(nums)
One line of math. One line of code.
The solution
def minMoves(self, nums):
return sum(nums) - len(nums) * min(nums)
That is the complete solution. Here is the reasoning behind each part:
min(nums)finds the smallest element. This is the target value every element needs to reach (in the decremented view).len(nums) * min(nums)is what the total sum would be if every element were already equal to the minimum.sum(nums) - len(nums) * min(nums)is the total "excess" across all elements. Each unit of excess requires exactly one decrement (one move), so this is the answer.
You can also think of it as summing the differences: for each element, compute nums[i] - min(nums), then add them all up. That gives sum(nums) - n * min(nums) after expanding.
Visual walkthrough
Let's trace through [1, 2, 3] step by step to see how the formula works.
Step 1: Reframe the problem
Incrementing n-1 elements by 1 is equivalent to decrementing 1 element by 1. Now the goal is: bring every element down to the minimum.
Step 2: Find the minimum
The minimum element is 1. Every other element needs to be reduced to 1.
Step 3: Sum the differences
Moves = (2-1) + (3-1) = 1 + 2 = 3. This equals sum(nums) - n * min(nums) = 6 - 3*1 = 3.
Step 4: Result
After 3 moves, all elements equal the minimum. Formula: sum(nums) - n * min(nums) = 3.
Notice how once you reframe the problem as "decrement to the minimum," the answer falls out immediately. There is no simulation needed. You just compute the gap between each element and the minimum, then sum those gaps.
Complexity analysis
| Aspect | Value |
|---|---|
| Time | O(n) |
| Space | O(1) |
| Difficulty | Medium |
Time: O(n) because you scan the array once to compute the sum and once to find the minimum. Both are linear passes (and many languages compute them in a single pass internally).
Space: O(1) because you only store the sum and the minimum. No extra arrays or data structures are needed.
The building blocks
This problem is built from one core building block:
Reframing an operation into its equivalent. Incrementing n - 1 elements by 1 is equivalent to decrementing 1 element by 1. Once you see this, the problem reduces to a simple summation. This reframing technique appears in many math-based problems. For example, in problems involving circular arrays or modular arithmetic, restating the operation in a different form often reveals a closed-form solution. The skill is to ask: "What does this operation look like from the other side?"
Edge cases
- All elements equal.
[5, 5, 5]returns 0. No moves needed sincesum - n * min = 15 - 3*5 = 0. - Two elements.
[1, 5]returns 4. You need 4 moves to close the gap. - Single element.
[7]returns 0. Only one element, so it is already "equal." - Large gaps.
[1, 1000000000]returns 999999999. The formula handles large values without issue since there is no simulation. - All same except one.
[1, 1, 1, 100]returns 99. Only the outlier contributes to the total.
From understanding to recall
The entire solution is one line, but the insight behind it is what matters. Under time pressure, you need to remember: "increment n-1 is the same as decrement 1." That single reframing gives you the formula.
Practice reconstructing the reasoning, not just the code. Start from the equivalence, derive the formula, and write the one-liner. After a few reps with spaced repetition, this pattern will be automatic. And the general skill of reframing operations will help you on other problems where brute force hides a clean mathematical solution.
Related posts
- Plus One - Another array math problem where a simple operation on digits requires careful handling of edge cases
- Move Zeroes - An array manipulation problem where reframing what you move (zeroes vs non-zeroes) simplifies the solution
- Missing Number - Uses a sum-based formula to find the answer in O(n) time and O(1) space, similar to this problem's approach