Move Zeroes
Problem
nums, move every 0 to the end
while keeping the relative order of the non-zero elements. Do it in-place
(no copy of the array).[0,1,0,3,12]Output[1,3,12,0,0][0]Output[0]1 ≤ n ≤ 104 · -231 ≤ nums[i] ≤ 231-1 · Follow-up: minimise total operations.
Try it yourself
class Solution {
public void moveZeroes(int[] nums) {
}
}
Instinct "In place", "O(1) extra space" or "one pass" over an array? Think write pointer, reversal, prefix/suffix passes or using indices as storage.
Memory hack Read fast, write slow, reverse to rotate, and let the index be the hash.
Open the Array Manipulation guide →Approaches
Brute ForceExtra Array (Copy & Fill)
O(n)Space O(n)Copy every non-zero into a new array result in order, fill the
remaining slots with 0, then copy result back into
nums.
public void moveZeroes(int[] nums) { int n = nums.length; int[] result = new int[n]; int j = 0; // First pass: accumulate non-zero elements for (int i = 0; i < n; i++) { if (nums[i] != 0) { result[j] = nums[i]; j++; } } // Second pass: fill remaining positions with zeroes for (; j < n; j++) { result[j] = 0; } // Copy back to original array System.arraycopy(result, 0, nums, 0, n); }
Easy to reason about, but uses O(n) extra memory and breaks the in-place rule.
BetterTwo Pointers — Overwrite, then Fill
O(n)Space O(1)Use the front of nums itself as result. Write pointer
insertPos never overtakes read pointer i, so we never
overwrite a value we still need. After the scan, set
nums[insertPos..n-1] = 0.
public void moveZeroes(int[] nums) { int insertPos = 0; // index where the next non-zero goes for (int i = 0; i < nums.length; i++) { if (nums[i] != 0) { nums[insertPos] = nums[i]; insertPos++; } } // Fill the rest of the array with zeroes while (insertPos < nums.length) { nums[insertPos] = 0; insertPos++; } }
In-place, but always does n writes and needs a second fill loop.
OptimalTwo Pointers — Single-Pass Swap
O(n)Space O(1)Swap instead of overwrite, so no fill loop is needed. Invariant:
nums[0..z-1] = non-zeros in order, nums[z..c-1] = zeros.
Each swap rolls the “zero block” one step right, like a snowball.
public void moveZeroes(int[] nums) { int lastZeroPosition = 0; // start of the zero block for (int current = 0; current < nums.length; current++) { if (nums[current] != 0) { int temp = nums[lastZeroPosition]; nums[lastZeroPosition] = nums[current]; nums[current] = temp; lastZeroPosition++; } } }
Dry run[0,1,0,3,12]
- c=00c z103120 → skip
- c=110c z0312swap(0,1), z=1
- c=210z0c3120 → skip
- c=3130z0c12swap(1,3), z=2
- c=413120z0swap(2,4), z=3 ✔
Single pass, in-place, and writes only when needed — answers the follow-up.
if (current != lastZeroPosition) — an array
with no zeros then does zero writes.At a glance
| Level | Approach | Time | Space |
|---|---|---|---|
| Brute Force | Extra Array (Copy & Fill) | O(n) | O(n) |
| Better | Two Pointers — Overwrite, then Fill | O(n) | O(1) |
| Optimal | Two Pointers — Single-Pass Swap | O(n) | O(1) |
- Swapping when
nums[i] == 0— moves zeros forward. - Forgetting the fill loop (Better) — leaves stale values like
[1,3,12,3,12]. - Left/right swaps or sorting — destroys the relative order of non-zeros.
- Start with the extra-array idea, then point out it breaks the in-place rule.
- State the invariant: everything left of
zis non-zero and in order. - Raise the follow-up yourself: the swap version minimises writes.