Advertisement
Home Data Structure Arrays Move All Zeros to the Beginning of an Array

Move All Zeros to the Beginning of an Array

2
Advertisement

Title: Move All Zeros to the Beginning of an Array

Rearranging an array in place is a classic interview question because it tests whether you can mutate memory safely without allocating a second buffer. In this guide, we will explore how to move every zero in a Java int array to the beginning while preserving the relative order of the non-zero elements. You will learn a clean two-pass algorithm, see it traced step by step, and understand the mistakes that turn a one-line idea into a very bad bug.

By the end, you will be able to write the method from scratch, reason about its time and space complexity, and answer the follow-up questions that interviewers typically ask once the base solution is on the whiteboard.

Understanding the Problem

You are given an integer array such as {4, 0, 1, 0, 2, 0, 5}. You must rearrange it so that every 0 sits at the front of the array and every non-zero value shifts to the right, keeping its original left-to-right order. The expected result for the sample input is {0, 0, 0, 4, 1, 2, 5}.

The constraint that makes this interesting is doing the work in place, using only a few extra variables. That rules out building a new array and copying values back; we must mutate the input directly in O(1) extra space.

Approach: Two-Pass Right-to-Left Scan

The trick is to walk the array from the right end toward the left. We keep a writeIndex that marks where the next non-zero value should land. Because writeIndex only moves when we actually place a value, it is always at or ahead of our read pointer, so we never clobber an unread element. Once the scan ends, every slot before writeIndex is still waiting to be filled, so we zero them out.

  1. Guard against a null array or an array of length zero and return immediately.
  2. Initialize writeIndex to nums.length - 1, the last valid index.
  3. Loop over the array from the last index down to index 0 using a read pointer i.
  4. If nums[i] is non-zero, copy it to nums[writeIndex] and decrement writeIndex.
  5. If nums[i] is zero, do nothing; the right side already has or will receive a value.
  6. After the loop, fill every index from writeIndex down to 0 with 0.
  7. Return control to the caller; the array has been rearranged in place.

Java Program

The full program below defines the method moveZerosToBeginning and a main that exercises it. It is self-contained and ready to copy into a file named MoveZerosToBeginning.java.

Java
import java.util.Arrays;

public class MoveZerosToBeginning {
    // Moves all zeros in the input array to the beginning,
    // preserving the relative order of the non-zero elements.
    public static void moveZerosToBeginning(int[] nums) {
        if (nums == null || nums.length == 0) {
            return;
        }
        int writeIndex = nums.length - 1;
        // Pass 1: scan from right to left and copy every
        // non-zero value toward the right side of the array.
        for (int i = nums.length - 1; i >= 0; i--) {
            if (nums[i] != 0) {
                nums[writeIndex] = nums[i];
                writeIndex--;
            }
        }
        // Pass 2: fill the untouched prefix with zeros.
        while (writeIndex >= 0) {
            nums[writeIndex] = 0;
            writeIndex--;
        }
    }

    public static void main(String[] args) {
        int[] nums = {4, 0, 1, 0, 2, 0, 5};
        System.out.println("Before: " + Arrays.toString(nums));
        moveZerosToBeginning(nums);
        System.out.println("After:  " + Arrays.toString(nums));
    }
}

Explanation of the Program

The method moveZerosToBeginning starts with a defensive check so that calling it with null or an empty array is a safe no-op. After that, it declares writeIndex at the last index of the array, which is the slot where the first non-zero value found from the right will land.

The first for loop runs the read pointer i from nums.length - 1 down to 0. Whenever nums[i] is non-zero, the value is copied to nums[writeIndex] and writeIndex is decremented. When nums[i] is 0, nothing is written; the zero is effectively discarded because the second loop will later overwrite its slot.

The second while loop then fills every index from writeIndex down to 0 with 0. Because the first loop never let writeIndex fall below the read pointer i, these are precisely the slots that no non-zero value needed, so the overwrite is safe. The result is the input array mutated in place, with zeros packed to the front and non-zeros in their original order on the right.

Step-by-Step Trace

Consider the input [0, 2, 0, 5, 7], which should become [0, 0, 2, 5, 7]. The table below shows one row per iteration of the first for loop; writeIndex starts at 4.

Iterationinums[i]nums[i] != 0?writeIndex (before)Array after stepwriteIndex (after)
147yes4[0, 2, 0, 5, 7]3
235yes3[0, 2, 0, 5, 7]2
320no2[0, 2, 0, 5, 7]2
412yes2[0, 2, 2, 5, 7]1
500no1[0, 2, 2, 5, 7]1

After the first loop ends, the second loop fills indices 1 and 0 with 0, producing the final array [0, 0, 2, 5, 7]. At the end of each iteration of the first loop, the invariant holds: nums[writeIndex + 1 .. nums.length - 1] contains every non-zero value from the already-scanned portion in its original left-to-right order.

Examples

Example 1: Mixed Zeros and Non-Zeros

An array with zeros scattered through the middle. The non-zero order 5, 3, 1 is preserved on the right side.

Java
int[] arr = {5, 0, 3, 0, 1};
moveZerosToBeginning(arr);
// Output: [0, 0, 5, 3, 1]

Example 2: Zeros Already at the Front

If the zeros are already clustered at the beginning, the algorithm still runs but writes each non-zero to the slot it already occupies, so the array is unchanged.

Java
int[] arr = {0, 0, 0, 1, 2};
moveZerosToBeginning(arr);
// Output: [0, 0, 0, 1, 2]

Example 3: Array Contains No Zeros

When the input has no zeros at all, every slot is a self-copy and the second loop never executes, so the array stays identical.

Java
int[] arr = {7, 1, 8, 3, 4};
moveZerosToBeginning(arr);
// Output: [7, 1, 8, 3, 4]

Common Mistakes to Avoid

Four pitfalls trip up almost every candidate on this problem, usually in the same order; watch for them in your own solution before you move on.

  • Scanning left to right – on input {0, 1, 0, 2} a left-to-right version happily overwrites nums[0] before it has saved the 1, producing {1, 1, 2, 2}. Scan right to left (or use a staged two-pointer) so that the write index is always at or behind the read index.
  • Forgetting to zero the prefix – after the first loop, indices 0..writeIndex still hold leftover values from the input, producing output like {4, 0, 1, 4, 1, 2, 5}. Add the second loop that writes 0 to every remaining slot.
  • Starting writeIndex at nums.length – the first non-zero write then lands at index nums.length and throws ArrayIndexOutOfBoundsException. Initialize writeIndex = nums.length - 1, the last valid index.
  • Using a less-than comparison – writing nums[i] < 0 or nums[i] > 0 instead of nums[i] != 0 silently drops valid negative inputs on arrays like {-3, 0, 4}. Compare against zero with != because the problem is about zeros, not sign.

Edge Cases to Test

Walk through these inputs before claiming the solution is done; most are one-liners to add to a unit test.

  • Empty array
  • Single-element array containing 0
  • Single-element array containing a non-zero value
  • Array of all zeros
  • Array with no zeros
  • Alternating zeros and non-zeros
  • Zeros clustered only at the end
  • Negative values present alongside zeros
  • Null array reference

Additional Considerations

The time complexity is O(n) because each of the two loops visits every index at most once. The space complexity is O(1); only writeIndex and the loop counter i are allocated, so this is a true in-place rearrangement.

The algorithm performs at most n writes in the first pass and at most n writes in the second pass, so the total work is bounded by 2n. In the common case where a few zeros are scattered through a large array, the second pass terminates very quickly because writeIndex is already close to -1.

Note that this is a mutating method: the caller sees the input array change. If callers depend on the original array staying intact, document the mutation clearly or return a defensive copy from a wrapper method.

Interview Follow-up Questions

Once the base solution is on the board, interviewers typically push on the following variants to see how deeply you understand the invariant.

  • What if you must move zeros to the end instead of the beginning? – mirror the algorithm: scan left to right with a writeIndex starting at 0, then pad the tail with zeros.
  • What if the relative order of non-zero values does not need to be preserved? – use two pointers from opposite ends and swap, which cuts the number of writes to the number of zeros.
  • What if the input is an Integer[] that may contain null values? – decide whether null is treated as zero or as a non-zero sentinel and guard the comparison with Objects.equals.
  • What if the array is streamed from disk and does not fit in memory? – make two passes over the stream: the first counts zeros while writing non-zeros to a scratch sink, the second emits the counted zeros followed by the scratch contents.

Conclusion

Moving zeros to the beginning of an array is a compact exercise that rewards thinking about pointers rather than reaching for extra storage. The two-pass right-to-left scan runs in linear time, uses constant extra space, and keeps the non-zero order intact, which is exactly what interviewers want to see on an in-place rearrangement question.

Try adapting the code to the mirror problem of moving zeros to the end, or extending it to work on an Integer[] with nulls. You can learn more about array interview problems in our Arrays category: dailyjavaconcept.com/category/arrays.