TechByteByByte

Move Zeroes to the End of an Array While Maintaining Order - Java

A medium QA/automation coding interview question: move Zeroes to the End of an Array While Maintaining Order, with a full Java walkthrough, dry run, and common interviewer follow-ups.

#Arrays#Two Pointers#In-place Algorithms#Medium#Java

Category: Medium | Concepts used: Two-pointer technique, in-place array modification


Problem Statement

Given an array, move all 0s to the end, while keeping the relative order of the non-zero elements unchanged. Must be done in-place (modifying the original array).

Input : [0, 1, 0, 3, 12]      Output: [1, 3, 12, 0, 0]

Examples (with edge scenarios)

#InputOutputWhy
1[0, 1, 0, 3, 12][1, 3, 12, 0, 0]Non-zero elements keep their relative order
2[] (empty)[]Nothing to move
3[0, 0, 0][0, 0, 0]All zeroes — nothing changes visibly
4[1, 2, 3] (no zeroes)[1, 2, 3]Unchanged — nothing to move
5[4, 0, 0, 5, 0, 6][4, 5, 6, 0, 0, 0]Multiple zeroes scattered throughout

Common Fresher Mistake

MistakeWhat happensFix
Creating a brand-new array to build the resultWorks, but violates the “in-place” requirement often specified for this exact problemUse a two-pointer swap technique on the original array instead
Simply removing zeroes and appending them at the end using extra listsAlso works, but again typically not what’s asked when “in-place” is specifiedPractice the swap-based two-pointer version, since that’s what’s usually expected

Before You Code: Clarify the Contract

Before choosing an algorithm, confirm whether the array may be null or empty, whether duplicates and original order matter, whether the method may modify the input, and whether the answer should contain values or original indices. These choices can change both the code and the best data structure.

Analogy: Conveyor Belt Sorter

Imagine you are at a recycling center with a conveyor belt of mixed items (numbers) and empty spaces (zeroes):

  • You have a pointer called insertPos that marks the beginning of the belt where clean items should be placed.
  • A scanner pointer i moves along the belt checking each slot:
    • When scanner i finds a real item (non-zero), you swap it into the slot pointed to by insertPos.
    • You then step the insertPos pointer forward by 1 (insertPos++), ready for the next item.
    • If scanner i finds an empty space (zero), you do nothing and just move i forward.
  • Since you are constantly swapping real items forward, all the empty spaces (zeroes) naturally get pushed back to the tail of the conveyor belt!

Solution 1 — Using an Extra Array (Simple, But Not In-Place)

Intuition

Walk through the array once, copying every non-zero value into a new result array as we go. Once all non-zero values are placed, fill whatever’s left over at the end with zeroes — this naturally groups all the zeroes at the tail.

import java.util.Arrays;

public class MoveZeroesExtraArray {
    public static int[] moveZeroes(int[] arr) {
        int[] result = new int[arr.length];
        int index = 0;

// first, copy all non-zero values in order
        for (int num : arr) {
            if (num != 0) {
                result[index++] = num;
            }
        }
        // remaining slots are already 0 by default in Java (int arrays init to 0)
        return result;
    }

public static void main(String[] args) {
        System.out.println(Arrays.toString(moveZeroes(new int[]{0, 1, 0, 3, 12}))); // [1, 3, 12, 0, 0]
    }
}

Output:

[1, 3, 12, 0, 0]

Interviewer’s take

This is correct and easy to explain, but it uses O(n) extra space and creates a whole new array — which usually isn’t what’s wanted when the question specifically says “in-place.” Good to mention as the “obvious first idea” but be ready to convert to Solution 2.

Follow-up questions you might get:

  • “Can you do this without creating a new array?” → leads to Solution 2.

Intuition

Keep a pointer (insertPos) marking “the next spot where a non-zero value should go.” Walk through the array with a second pointer; every time you find a non-zero value, swap it into the insertPos slot and advance insertPos. Since we only ever swap non-zero values forward into earlier positions, all the zeroes naturally get pushed toward the back, in the same relative order they were passed over.

import java.util.Arrays;

public class MoveZeroesInPlace {
    public static void moveZeroes(int[] arr) {
        int insertPos = 0; // where the next non-zero value should go

for (int i = 0; i < arr.length; i++) {
            if (arr[i] != 0) {
                // swap arr[i] and arr[insertPos]
                int temp = arr[insertPos];
                arr[insertPos] = arr[i];
                arr[i] = temp;
                insertPos++;
            }
        }
    }

public static void main(String[] args) {
        int[] arr = {0, 1, 0, 3, 12};
        moveZeroes(arr);
        System.out.println(Arrays.toString(arr)); // [1, 3, 12, 0, 0]

int[] arr2 = {4, 0, 0, 5, 0, 6};
        moveZeroes(arr2);
        System.out.println(Arrays.toString(arr2)); // [4, 5, 6, 0, 0, 0]
    }
}

Output:

[1, 3, 12, 0, 0]
[4, 5, 6, 0, 0, 0]

Dry Run (arr = [0, 1, 0, 3, 12])

insertPos=0

i=0: arr[0]=0 -> skip (it's zero)
i=1: arr[1]=1 -> non-zero -> swap arr[0] and arr[1] -> arr=[1,0,0,3,12], insertPos=1
i=2: arr[2]=0 -> skip
i=3: arr[3]=3 -> non-zero -> swap arr[1] and arr[3] -> arr=[1,3,0,0,12], insertPos=2
i=4: arr[4]=12 -> non-zero -> swap arr[2] and arr[4] -> arr=[1,3,12,0,0], insertPos=3

Final: [1, 3, 12, 0, 0]

Interviewer’s take

This is the preferred final answer — O(n) time, O(1) extra space (truly in-place), and preserves relative order of non-zero elements correctly through the swap mechanism. This two-pointer “partition” style pattern (one pointer scanning, one pointer marking where to place the next “good” element) is reused across many similar array-rearrangement problems.

Follow-up questions you might get:

  • “Why does swapping (not just overwriting) preserve correctness?” → Overwriting without swapping would lose the value that was originally at insertPos (unless it happened to be zero); swapping ensures we never lose track of any value — we just relocate it.
  • “What’s the minimum number of swaps performed?” → Exactly as many swaps as there are non-zero elements — no wasted work.

📊 Visual Flowchart

graph TD
    Start["Input Array arr"] --> Init["insertPos = 0"]
    Init --> Loop{"i < arr.length?"}
    Loop -->|Yes| CheckZero{"arr[i] != 0?"}
    CheckZero -->|Yes| Swap["swap arr[i] and arr[insertPos]"]
    Swap --> AdvanceIP["insertPos++"]
    CheckZero -->|No| Next["i++"]
    AdvanceIP --> Next
    Next --> Loop
    Loop -->|No| End["Return (Modified arr)"]

Final Verdict — Which Solution Should You Give?

Solution 1 (extra array)  ──O(n) space, not truly in-place──►  Okay as a starting idea
Solution 2 (two-pointer swap)  ──O(1) space, in-place────────►   PREFERRED FINAL ANSWER
  • Solution 2 is the expected final answer, especially since “in-place” is a standard requirement for this classic problem.

Quick Recap

ApproachTimeSpaceIn-place?
Extra arrayO(n)O(n)No
Two-pointer swapO(n)O(1)Yes
Author
TechByteByByte Editorial Team
Reviewed by
TechByteByByte Admin
Published
Last reviewed