LeetCode Β· #283

Move Zeroes Solution

Given an integer array nums, move all 0's to the end while maintaining the relative order of the non-zero elements. Do this in-place.

01
Section One Β· Problem

Problem Statement

🏷️

Difficulty

Easy

πŸ”—

LeetCode

Problem #283

πŸ—οΈ

Pattern

Two Pointers β€” read/write compaction

Given an integer array nums, move all 0's to the end of the array while maintaining the relative order of the non-zero elements. You must do this in-place without making a copy of the array.

Example
Input: nums = [0, 1, 0, 3, 12] Output: [1, 3, 12, 0, 0] // Non-zeros maintain order: 1, 3, 12. Zeros pushed to end.
Constraints
β€’ 1 ≀ nums.length ≀ 10⁴ β€’ -2Β³ΒΉ ≀ nums[i] ≀ 2Β³ΒΉ βˆ’ 1 β€’ Must be done in-place β€” no extra array
02
Section Two Β· Approach 1

Brute Force β€” Extra Array O(n)

Create a new array. First copy all non-zero elements, then fill the rest with zeros. Copy back to the original. Correct but violates the in-place constraint.

Why we can do better
Problem: Uses O(n) extra space. The read/write pointer technique compacts non-zeros forward in a single pass, then fills trailing positions with zeros β€” all in-place with O(1) space.
Java β€” Extra Array
class Solution { public void moveZeroes(int[] nums) { int[] temp = new int[nums.length]; int idx = 0; for (int n : nums) if (n != 0) temp[idx++] = n; System.arraycopy(temp, 0, nums, 0, nums.length); } }
Python β€” Extra Array
class Solution: def moveZeroes(self, nums: list[int]) -> None: non_zeros = [x for x in nums if x != 0] nums[:] = non_zeros + [0] * (len(nums) - len(non_zeros))
MetricValue
TimeO(n)
SpaceO(n) β€” violates in-place requirement
03
Section Three Β· Approach 2

Read/Write Pointer β€” O(n) time, O(1) space

Use a write pointer that tracks where the next non-zero should go. A read pointer scans the array. When the reader finds a non-zero value, swap it into the writer's position and advance both. Zeros naturally accumulate at the end.

πŸ’‘ Mental model: Imagine a conveyor belt with mixed packages and empty boxes. A worker (write pointer) stands at the start. A scanner (read pointer) moves along the belt. Every time the scanner finds an actual package, it swaps it to the worker's position, and the worker steps forward. Empty boxes slide to the end naturally.
Algorithm
  • Step 1: Initialize write = 0.
  • Step 2: For each read from 0 to nβˆ’1: if nums[read] β‰  0, swap nums[write] and nums[read], then write++.
  • Step 3: After the loop, all non-zeros are compacted to positions 0..writeβˆ’1, and zeros fill write..nβˆ’1.
🎯 When to recognize this pattern:
  • Any problem asking to partition or compact an array in-place β€” move certain elements to one side, remove duplicates (LC 26), or segregate values.
  • The signal is "rearrange in-place preserving relative order." The read/write (or slow/fast) pointer pattern appears in LC 283, LC 26 (Remove Duplicates), LC 27 (Remove Element), and LC 75 (Sort Colors).
04
Section Four Β· Trace

Visual Walkthrough

Trace through nums = [0, 1, 0, 3, 12]:

Read/Write Pointer β€” compact non-zeros forward
INITIAL 0 1 0 3 12 r=0: nums[0]=0 β†’ skip (it's zero) r=1: nums[1]=1 β‰  0 β†’ swap(w=0, r=1) β†’ [1, 0, 0, 3, 12], w=1 r=2: nums[2]=0 β†’ skip r=3: nums[3]=3 β‰  0 β†’ swap(w=1, r=3) β†’ [1, 3, 0, 0, 12], w=2 r=4: nums[4]=12 β‰  0 β†’ swap(w=2, r=4) β†’ [1, 3, 12, 0, 0], w=3 RESULT 1 3 12 0 0 Answer: [1, 3, 12, 0, 0] βœ“
05
Section Five Β· Implementation

Code β€” Java & Python

Java β€” Read/Write Swap
class Solution { public void moveZeroes(int[] nums) { int write = 0; for (int read = 0; read < nums.length; read++) { if (nums[read] != 0) { int temp = nums[write]; // swap write ↔ read nums[write] = nums[read]; nums[read] = temp; write++; } } } }
Python β€” Read/Write Swap
class Solution: def moveZeroes(self, nums: list[int]) -> None: write = 0 for read in range(len(nums)): if nums[read] != 0: nums[write], nums[read] = nums[read], nums[write] write += 1
06
Section Six Β· Analysis

Complexity Analysis

ApproachTimeSpaceTrade-off
Extra ArrayO(n)O(n)Simple but violates in-place constraint
Two-pass (compact + fill)O(n)O(1)First pass moves non-zeros, second fills zeros
Swap ← optimal O(n) O(1) Single pass, in-place swap. Minimizes writes.
07
Section Seven Β· Edge Cases

Edge Cases & Pitfalls

CaseInputWhy It Matters
No zeros[1, 2, 3]Write follows read exactly β€” array unchanged. Zero swaps with itself.
All zeros[0, 0, 0]Write never advances β€” all elements stay zero.
Single element[0] or [5]Trivial β€” nothing to move.
Zeros at end[1, 2, 0, 0]Already in correct position β€” write catches up, self-swaps.
Negative numbers[0, -1, 0, -3]Negatives are non-zero β€” treated like any other value.
⚠ Common Mistake: Using assignment instead of swap: nums[write] = nums[read] without zeroing nums[read]. This leaves the original non-zero in place, creating duplicates. Always swap β€” or use a two-pass approach where you fill zeros explicitly after compacting.

← Back to Two Pointers problems