easyLeetCodeNot Started

Move Zeroes

A curated StudyFlow practice problem with comprehensive editorial and multi-language solutions.

Solve on LeetCode
Lesson

Problem Statement

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

Note that you must do this in-place without making a copy of the array.

Example 1 · Standard Array with Interleaved Zeros:

Input: nums = [0, 1, 0, 3, 12]
Output: [1, 3, 12, 0, 0]
Explanation: The non-zero elements are 1, 3, 12 in their original order. The two zeros are shifted to the end.

Example 2 · Single Element Array:

Input: nums = [0]
Output: [0]
Explanation: Array contains only [0], which remains [0].

Example 3 · No Zeros in Array:

Input: nums = [1, 2, 3, 4]
Output: [1, 2, 3, 4]
Explanation: There are no zeros to shift, array remains unchanged.

Constraints:

  • 1 <= nums.length <= 104
  • -231 <= nums[i] <= 231 - 1

Prerequisites

Before attempting this problem, you should be comfortable with:

  • Two Pointers technique (fast and slow pointer)
  • In-place array swapping
  • Understanding stability / relative order preservation

What You'll Learn

Key principles and algorithmic techniques you will master from this problem:

  • Master the Slow/Fast Two Pointers in-place compaction pattern.
  • Understand the difference between two-pass write+fill vs single-pass swap.
  • Minimize unnecessary array writes when the array already has no zeros.
  • Implement clean, standalone solutions across C++, Java, Python, and JavaScript.

Pattern Recognition Trigger

How to instantly recognize this algorithmic pattern when encountering unseen interview questions:

Signals to Look For:

  • Asked to move a specific target value (e.g. 0) to one end of the array.
  • Relative ordering of all other elements must be strictly preserved (stable partition).
  • Must be performed in-place with O(1) auxiliary space.

Algorithmic Decision Tree:

  • Use Slow/Fast Two Pointers: write pointer tracks position for non-zeros; read pointer scans for non-zeros and swaps.

Connected Patterns:

Two PointersSliding WindowPrefix Sum

1. Brute Force — Auxiliary Array

Intuition

Copy all non-zero elements into a new array, then copy them back to nums and fill the remaining spots with zeros.

Algorithm

  1. Initialize an empty list temp.
  2. For each number x in nums:
  3. If x != 0, append x to temp.
  4. Copy elements from temp to nums[0 ... temp.length - 1].
  5. Fill nums[temp.length ... nums.length - 1] with 0.

Bubble Adjacent Swaps (O(N^2) Time)

2 of 2 questions left today
Step 1 / 6
Trace timeline17% explored
Current operationSTEP 1 OF 6
Zero bubbles one position to the right
Visual state
Values and pointers at this exact step
pointers
S
0
1
0
3
12
0
↑ swap
1
↑ swap
2
3
4
Variables at this step
pass
1
swapped
true
Check / comparison
nums[0] is 0 and nums[1] is 1: swap adjacent pair
Decision / next transition
Array becomes [1, 0, 0, 3, 12].
Why this step matters

Zero bubbles one position to the right.

Step 1 / 6
C++ SOLUTIONCLEAN & OPTIMIZED
1#include <iostream>
2#include <vector>
3using namespace std;
4
5// Brute Force: Auxiliary array copy (O(N) space)
6void moveZeroes(vector<int>& nums) {
7 vector<int> temp;
8 for (int num : nums) {
9 if (num != 0) {
10 temp.push_back(num);
11 }
12 }
13
14 for (size_t i = 0; i < temp.size(); i++) {
15 nums[i] = temp[i];
16 }
17 for (size_t i = temp.size(); i < nums.size(); i++) {
18 nums[i] = 0;
19 }
20}
21
22int main() {
23 vector<int> nums = {0, 1, 0, 3, 12};
24 moveZeroes(nums);
25
26 cout << "Output: [";
27 for (size_t i = 0; i < nums.size(); i++) {
28 cout << nums[i] << (i + 1 < nums.size() ? ", " : "");
29 }
30 cout << "]" << endl;
31 return 0;
32}

Time & Space Complexity

  • Time complexity: O(N^2) — Time complexity for Approach 1: Brute Force — Auxiliary Array.
  • Space complexity: O(1) — Space complexity for Approach 1: Brute Force — Auxiliary Array.

Why Brute Force Doesn't Scale:

For N = 105, quadratic O(N2) approaches require ~1010 operations, exceeding the standard 1-second CPU budget.

The optimal approach processes N elements in a single or logarithmic pass, completing in under 10ms with minimal memory footprint.


2. Better — Two-Pass In-Place Overwrite

Intuition

First pass: shift all non-zero elements to the front of nums using a write pointer. Second pass: fill all indices from write to end with 0.

Algorithm

  1. Initialize write = 0.
  2. Loop i from 0 to nums.length - 1:
  3. If nums[i] != 0:
  4. nums[write] = nums[i].
  5. write++.
  6. Loop j from write to nums.length - 1:
  7. nums[j] = 0.

Auxiliary Buffer Copy (O(N) Time, O(N) Space)

2 of 2 questions left today
Step 1 / 6
Trace timeline17% explored
Current operationSTEP 1 OF 6
Zeros are filtered out on the first pass
Visual state
Values and pointers at this exact step
pointers
S
0
1
0
3
12
0
↑ read
1
2
3
4
Variables at this step
read
0
buffer
[]
Check / comparison
nums[0] == 0: zero detected
Decision / next transition
Do not append to buffer. buffer = [].
Why this step matters

Zeros are filtered out on the first pass.

Step 1 / 6
C++ SOLUTIONCLEAN & OPTIMIZED
1#include <iostream>
2#include <vector>
3using namespace std;
4
5// Better: Two-pass overwrite & zero-fill (O(N) time, O(1) space)
6void moveZeroes(vector<int>& nums) {
7 int write = 0;
8 int n = nums.size();
9
10 // Pass 1: Shift non-zeros forward
11 for (int i = 0; i < n; i++) {
12 if (nums[i] != 0) {
13 nums[write] = nums[i];
14 write++;
15 }
16 }
17
18 // Pass 2: Fill remaining with zeros
19 while (write < n) {
20 nums[write] = 0;
21 write++;
22 }
23}
24
25int main() {
26 vector<int> nums = {0, 1, 0, 3, 12};
27 moveZeroes(nums);
28
29 cout << "Output: [";
30 for (size_t i = 0; i < nums.size(); i++) {
31 cout << nums[i] << (i + 1 < nums.size() ? ", " : "");
32 }
33 cout << "]" << endl;
34 return 0;
35}

Time & Space Complexity

  • Time complexity: O(N log N) — Time complexity for Approach 2: Better — Two-Pass In-Place Overwrite.
  • Space complexity: O(N) — Space complexity for Approach 2: Better — Two-Pass In-Place Overwrite.

3. Optimal — Single-Pass Two Pointers Swap (Minimal Writes)

Intuition

Maintain write pointer for the first zero; whenever read finds a non-zero, swap nums[write] and nums[read], advancing write by 1.

Algorithm

  1. Initialize write = 0.
  2. Loop read from 0 to nums.length - 1:
  3. If nums[read] != 0:
  4. Swap nums[write] with nums[read].
  5. write++.

Two Pointers Write-Index In-Place (O(N) Time, O(1) Space)

2 of 2 questions left today
Step 1 / 6
Trace timeline17% explored
Current operationSTEP 1 OF 6
The write pointer remains stationary at index 0 waiting for the first non-zero element
Visual state
Values and pointers at this exact step
pointers
S
0
1
0
3
12
0
↑ write↑ read
1
2
3
4
Variables at this step
write
0
read
0
Check / comparison
read = 0: nums[0] == 0. Zero encountered
Decision / next transition
Do not advance write. Increment read to 1.
Why this step matters

The write pointer remains stationary at index 0 waiting for the first non-zero element.

Step 1 / 6
C++ SOLUTIONCLEAN & OPTIMIZED
1#include <algorithm>
2#include <iostream>
3#include <vector>
4using namespace std;
5
6// Optimal: Single-Pass Two Pointers Swap (O(N) time, O(1) space)
7void moveZeroes(vector<int>& nums) {
8 int write = 0;
9
10 for (size_t read = 0; read < nums.size(); read++) {
11 if (nums[read] != 0) {
12 swap(nums[write], nums[read]);
13 write++;
14 }
15 }
16}
17
18int main() {
19 vector<int> nums = {0, 1, 0, 3, 12};
20 moveZeroes(nums);
21
22 cout << "Output: [";
23 for (size_t i = 0; i < nums.size(); i++) {
24 cout << nums[i] << (i + 1 < nums.size() ? ", " : "");
25 }
26 cout << "]" << endl;
27 return 0;
28}

Time & Space Complexity

  • Time complexity: O(N) — Time complexity for Approach 3: Optimal — Single-Pass Two Pointers Swap (Minimal Writes).
  • Space complexity: O(1) — Space complexity for Approach 3: Optimal — Single-Pass Two Pointers Swap (Minimal Writes).

Approach Comparison Matrix

Side-by-side comparison of time, space, and algorithmic trade-offs across each approach:

ApproachTimeSpaceCore IdeaTrade-off / Bottleneck
1.Auxiliary ArrayO(N)O(N)Very easy to understand.Baseline only.
2.Two-Pass OverwriteO(N)O(1)Simple in-place logic.Good step, but interviewer will ask for a single pass.
3.Single-Pass SwapOptimalO(N)O(1)Optimal single pass, minimal total array writes, clean 4-line code.Optimal gold standard.

Common Pitfalls & Crucial Edge Cases

Off-by-One Errors

Incorrect boundary indexing when adjusting pointers or array slices.

Integer Overflow

Using 32-bit signed integer types when accumulative operations exceed 231 - 1 in C++/Java.

Unnecessary Memory Allocation

Allocating large auxiliary arrays or objects inside inner loops causing GC overhead.

Failing to Reset Loop State

Not re-initializing state variables or counters between iterations or subproblems.

Crucial Edge Cases to Validate:

  • Array with All Zeros — Input: nums = [0, 0, 0, 0], Expected: [0, 0, 0, 0] — No non-zero elements exist; write remains at index 0 and array stays all zeros without errors.
  • Array with No Zeros — Input: nums = [1, 2, 3, 4], Expected: [1, 2, 3, 4] — Write and read move together without corrupting original ordering.
  • Leading Zeros Followed by Non-Zeros — Input: nums = [0, 0, 1], Expected: [1, 0, 0] — Non-zero 1 must swap directly into index 0.

Interview Tips & Best Practices

How to communicate your thought process and address follow-ups in a live technical interview:

  1. Clarifying Questions — Confirm: 'Should the relative order of non-zero elements be maintained?' (Yes, this is critical and rules out bidirectional two pointers).
  2. Code Explanation — Explain the partition invariant: 'All elements to the left of write are processed non-zeros; all elements between write and read are zeros.'
  3. Follow-up — Be ready for follow-up: 'How to minimize the number of write operations?' (Add an if (write != read) check before swapping).

Quick Comprehension Check

Test your intuitive understanding of the core concept in 30 seconds:

1.What is the optimal time and auxiliary space complexity for Move Zeroes?

2.Why is the brute force approach suboptimal for large inputs in Move Zeroes?

3.Which data structure or technique enables the optimal solution for Move Zeroes?