Move Zeroes · Optimal Solution

Compact forward, fill behind.

A sensor grid streams readings where zero means "no signal." Before downstream processing, you must pack all live readings to the front — preserving their original order — then zero-fill the vacated tail. Two pointers do it in one pass: a read pointer scans every element, a write pointer accepts only non-zeroes. When the scan finishes, fill from write to the end with zeroes. O(n) time. O(1) space.


Interactive

Watch the pointers diverge


Concept

The write pointer invariant

The read pointer visits every element exactly once. The write pointer advances only when a non-zero value is placed. This means write ≤ read at all times — non-zeroes land only in already-scanned territory, preserving order.

read pointer

Scans left to right, examining every element. Advances unconditionally on each iteration.

write pointer

Marks the next available slot for a non-zero value. Advances only when a live value is placed.

zero fill

After the scan, every position from write to the end is a vacated slot that must become zero.


Algorithm

Scan once, compact, then fill

The algorithm runs in two phases. Phase one compacts non-zero values to the front. Phase two fills the remainder with zeroes.

  1. 1

    Initialize write pointer at 0

    The write pointer starts at the beginning — the first slot where a non-zero value can land.

  2. 2

    Scan with read pointer

    For each element: if nums[read] ≠ 0, copy it to nums[write] and advance write. Otherwise, skip — the read pointer moves on.

  3. 3

    Fill the tail with zeroes

    From write to the end, set every element to 0. These are the slots vacated by compaction.


Edge Cases

Where the pointers tell the story

The gap between read and write reveals the algorithm's behaviour under different inputs.

No zeroes at all

When every element is non-zero, the write pointer tracks the read pointer exactly — every value copies to itself. The fill phase writes nothing. The algorithm degrades gracefully to a no-op.

All zeroes

When every element is zero, the write pointer never advances. The fill phase rewrites the entire array with zeroes — effectively a no-op, since the values were already zero. The read pointer alone does all the work.

Zeroes only at the end

The write pointer keeps pace with read through all non-zero elements, then stalls. The fill phase handles the trailing zeroes — which are already zero. No value actually moves.