AlgoMaster Logo

Move Zeroes

Last Updated: March 27, 2026

easy
3 min read

Move Zeroes

Understanding the Problem

At first glance, this looks trivial: just separate zeroes from non-zeroes. But there are two constraints that make it interesting. First, you need to preserve the relative order of non-zero elements. Second, you must do it in-place, meaning no new array.

The key observation is this: if you can figure out where each non-zero element should end up, the zeroes will naturally fill the remaining positions at the end. So the real question becomes: how do we efficiently place non-zero elements in their correct positions without disturbing their order?

Key Constraints:

  • 1 <= nums.length <= 10^4 → With n up to 10,000, O(n^2) would mean 100 million operations, which is tight but passable. O(n) is clearly preferred.
  • -2^31 <= nums[i] <= 2^31 - 1 → Full 32-bit integer range. Values can be negative, so "non-zero" includes negative numbers. Don't confuse "non-zero" with "positive."
  • in-place → The problem explicitly forbids creating a copy of the array. Any solution using O(n) extra space technically violates the constraint.

Approach 1: Extra Array

Intuition

The most straightforward way to think about this: collect all the non-zero elements in order, then fill the rest with zeroes. If we ignore the in-place constraint for a moment, we can use an extra array to build the result, then copy it back.

This approach won't satisfy the follow-up requirement, but it's a clean starting point that makes the logic crystal clear.

Algorithm

  1. Create a new array result of the same size as nums.
  2. Iterate through nums. For each non-zero element, place it at the next available position in result.
  3. The remaining positions in result are already zero (default values).
  4. Copy result back into nums.

Example Walkthrough

Input:

0
0
1
1
2
0
3
3
4
12
nums

After the first pass (collect non-zeroes into result):

0
1
1
3
2
12
3
0
4
0
result

Finally, we copy result back into nums:

0
1
1
3
2
12
3
0
4
0
nums

Code

This approach works correctly but uses extra space.

What if we placed non-zero elements directly into their final positions within the original array?

Approach 2: Two Pointers (Swap)

Intuition

We can use a single pointer insertPos to track where the next non-zero element should go. As we scan through the array, every time we find a non-zero element, we swap it into the insertPos position and advance the pointer.

Algorithm

  1. Initialize insertPos = 0 to track the next position for a non-zero element.
  2. Iterate through the array with index i from 0 to n - 1.
  3. When nums[i] is not zero, swap nums[i] with nums[insertPos], then increment insertPos.
  4. After the loop, all non-zeroes are at the front in their original order, and all zeroes are at the end.

Example Walkthrough

1Initialize: insertPos=0, i=0
0
insertPos
0
i
1
1
2
0
3
3
4
12
1/7

Code

Approach 3: Optimal (Minimal Operations)

Intuition

Approach 2 always performs a swap when it finds a non-zero element, even when i == insertPos, meaning the element is already where it belongs. In an array like [1, 2, 3, 0, 0], the first three iterations all do unnecessary self-swaps.

The fix is simple: only swap when i != insertPos. This skips redundant operations when non-zero elements are already in place. It's the same algorithm with a small guard condition, but in arrays with few zeroes (or zeroes concentrated at the end), this can significantly reduce the number of write operations.

Algorithm

  1. Initialize insertPos = 0.
  2. Iterate through the array with index i.
  3. When nums[i] is not zero:
    • If i != insertPos, swap nums[i] with nums[insertPos].
    • Increment insertPos.
  4. After the loop, all zeroes are at the end.

Example Walkthrough:

1Initialize: insertPos=0, i=0
0
insertPos
1
i
1
2
2
0
3
3
4
12
1/6

Code