AlgoMaster Logo

Move Zeroes

easyFrequency6 min readUpdated July 10, 2026

Understanding the Problem

Separating zeroes from non-zeroes is easy. Two constraints make the problem more than that. First, the relative order of the non-zero elements must be preserved. Second, the work has to happen in-place, with no second array.

Once every non-zero element is in its correct position, the zeroes can only fall into the remaining positions at the end. So the problem reduces to placing the non-zero elements in order, at the front, without using extra space.

Key Constraints:

  • 1 <= nums.length <= 10^4 → With n up to 10,000, an O(n) single pass handles the input comfortably, so there is no reason to settle for an O(n^2) shifting solution.
  • -2^31 <= nums[i] <= 2^31 - 1 → Values span the full signed 32-bit range and can be negative. The condition that matters is nums[i] != 0, not nums[i] > 0.
  • in-place → The array must be rearranged within its own storage. A solution that allocates an O(n) array violates this, which is what the follow-up about minimizing operations is pointing toward.

Approach 1: Extra Array

Intuition

Build the answer in a second array: walk through nums, append each non-zero element to the next slot of result, and leave the remaining slots as zero. Then copy result back over nums. This ignores the in-place requirement, so it does not satisfy the follow-up, but it separates the two concerns (order of non-zeroes, position of zeroes) and makes the logic easy to follow before optimizing for space.

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 is correct but allocates a second array of size n, which the in-place requirement rules out. The next approach removes that array by placing non-zero elements directly into the front of the original array as it scans.

Approach 2: Two Pointers (Swap)

Intuition

A single pointer insertPos marks where the next non-zero element belongs. Scanning the array with index i, every time nums[i] is non-zero we swap it into nums[insertPos] and advance insertPos. Zeroes are skipped, so they accumulate ahead of insertPos and are pushed toward the end by later swaps.

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 swaps on every non-zero element, including when i == insertPos and the element is already in place. In an array like [1, 2, 3, 0, 0], the first three iterations swap each element with itself, three wasted writes.

This version writes only when i != insertPos. When a non-zero element is already at its target slot, it advances insertPos without touching the array. The follow-up asks to minimize operations, and this is the gain: the array is modified only for non-zero elements that have to move, so on inputs with few zeroes most iterations do no writes at all.

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