Move Zeros to End
Java coding interview problem for Array Logic: Move Zeros to End.
Moving all zeros to the end of an array is one of the most frequently asked array interview problems.
Although the problem looks simple, it tests important concepts:
- Array traversal
- Two Pointer Technique
- In-place modification
- Stable ordering
- Space optimization
- Algorithm design
This problem is a foundation for many advanced problems:
- Remove duplicates from array
- Partition array
- Move negative numbers
- Sliding window problems
- Data transformation
What Does Moving Zeros Mean?
Given an array, move all zero values to the end while maintaining the relative order of all non-zero elements.
Example
Input:
[0,1,0,3,12]
Output:
[1,3,12,0,0]
Explanation:
Non-zero elements:
1,3,12
remain in the same order.
Zeros move to the end.
Another Example
Input:
[5,0,2,0,8,1]
Output:
[5,2,8,1,0,0]
Why Is This Question Asked in Interviews?
Interviewers ask this problem because it evaluates:
- Understanding of arrays
- Ability to modify data in-place
- Pointer manipulation
- Memory optimization
- Handling edge cases
Common interview variations:
- Move zeros to beginning
- Move negative numbers
- Remove duplicates
- Partition array around a value
- Move all null values
Real-World Applications
Data Processing
Large datasets often contain empty or invalid values.
Example:
Before processing:
[100,0,200,0,300]
After cleanup:
[100,200,300,0,0]
Valid data is processed first.
Image Processing
Pixel arrays may contain empty pixels represented by:
0
Moving them allows efficient processing.
Database Processing
Missing values may be represented as:
0
Data transformation pipelines can move invalid values separately.
Memory Management
Compaction algorithms move unused spaces toward the end.
Problem Statement
Given an integer array,
move all zeros to the end while maintaining the relative order of non-zero elements.
The operation should be performed in-place if possible.
Example 1
Input:
[0,1,0,3,12]
Output:
[1,3,12,0,0]
Example 2
Input:
[1,2,3]
Output:
[1,2,3]
No zeros exist.
Example 3
Input:
[0,0,1]
Output:
[1,0,0]
Example 4
Input:
[0,0,0]
Output:
[0,0,0]
Understanding Zero Movement
Consider:
[0,5,0,3,8]
We need to separate:
Non-zero values:
5,3,8
Zeros:
0,0
Final:
[5,3,8,0,0]
Stable Movement
A stable algorithm keeps the original order of non-zero elements.
Example:
Input:
[4,0,2,7,0,9]
Stable output:
[4,2,7,9,0,0]
Order:
4 → 2 → 7 → 9
is preserved.
Unstable Movement
An unstable algorithm may change the order.
Example:
Possible output:
[9,2,7,4,0,0]
Zeros are moved, but original ordering is lost.
Most interview problems expect:
Stable movement
Array Visualization
Input:
Index:
0 1 2 3 4
0 1 0 3 12
Find non-zero elements:
1
3
12
Move them forward:
1 3 12
Fill remaining positions:
0 0
Final:
1 3 12 0 0
Dry Run
Input:
[0,1,0,3,12]
Initial:
result position = 0
Read:
0
Ignore.
Read:
1
Place at index 0:
[1,1,0,3,12]
Read:
0
Ignore.
Read:
3
Place at index 1:
[1,3,0,3,12]
Read:
12
Place at index 2:
[1,3,12,3,12]
Fill remaining:
[1,3,12,0,0]
Approach 1 — Using Extra Array (Beginner Friendly)
The easiest solution is creating a new array.
The idea:
- Copy all non-zero elements.
- Fill remaining positions with zeros.
Algorithm
- Create new array.
- Maintain an index.
- Traverse original array.
- Copy non-zero values.
- Remaining positions stay zero.
Java Program
import java.util.Arrays;
public class MoveZerosExtraSpace {
public static int[] moveZeros(
int[] numbers) {
int[] result =
new int[numbers.length];
int index = 0;
for (int number : numbers) {
if (number != 0) {
result[index++] = number;
}
}
return result;
}
public static void main(String[] args) {
int[] numbers =
{0,1,0,3,12};
System.out.println(
Arrays.toString(
moveZeros(numbers)));
}
}
Output
[1,3,12,0,0]
Step-by-Step Explanation
Input:
[0,1,0,3,12]
Create:
[0,0,0,0,0]
Read:
0
Skip.
Read:
1
Copy:
[1,0,0,0,0]
Read:
3
Copy:
[1,3,0,0,0]
Read:
12
Copy:
[1,3,12,0,0]
Complexity Analysis
Time:
O(n)
Every element is visited once.
Space:
O(n)
New array is created.
Advantages
- Very easy to understand.
- Maintains order.
- Does not modify original array.
- Good beginner approach.
Drawbacks
- Requires extra memory.
- Not ideal when memory is limited.
- Not an in-place solution.
Approach 2 — Two Pointer Approach (Optimal)
The two pointer approach is the preferred interview solution.
It moves zeros without creating another array.
Two Pointer Concept
Use:
nonZeroIndex
to track where the next non-zero element should go.
Example:
Input:
[0,1,0,3,12]
Pointer:
nonZeroIndex = 0
Read:
1
Swap with index 0.
Result:
[1,0,0,3,12]
Read:
3
Swap with index 1.
Result:
[1,3,0,0,12]
Read:
12
Swap with index 2.
Result:
[1,3,12,0,0]
Algorithm
- Initialize pointer:
index = 0;
- Traverse array.
- Whenever non-zero value appears:
- Swap with index.
- Increment index.
Java Program
import java.util.Arrays;
public class MoveZerosTwoPointer {
public static void moveZeros(
int[] numbers) {
int index = 0;
for (int i = 0;
i < numbers.length;
i++) {
if (numbers[i] != 0) {
int temp =
numbers[index];
numbers[index] =
numbers[i];
numbers[i] =
temp;
index++;
}
}
}
public static void main(String[] args) {
int[] numbers =
{0,1,0,3,12};
moveZeros(numbers);
System.out.println(
Arrays.toString(numbers));
}
}
Output
[1,3,12,0,0]
Step-by-Step Explanation
Input:
[0,1,0,3,12]
index:
0
i = 0:
Value:
0
Skip.
i = 1:
Value:
1
Swap:
index 0 ↔ i 1
Array:
[1,0,0,3,12]
Increase index:
1
i = 3:
Value:
3
Swap:
index 1 ↔ i 3
Array:
[1,3,0,0,12]
i = 4:
Value:
12
Swap:
index 2 ↔ i 4
Array:
[1,3,12,0,0]
Complexity Analysis
Time:
O(n)
Space:
O(1)
Advantages
- Optimal solution.
- In-place modification.
- Maintains order.
- Interview recommended.
Drawbacks
- Slightly harder than extra array.
- Modifies original array.
Approach 3 — Swap Optimization Approach
The two pointer approach can be slightly optimized.
Instead of always swapping values, we can:
- Move non-zero elements forward.
- Fill remaining positions with zeros.
This reduces unnecessary swaps.
Example
Input:
[0,1,0,3,12]
Move non-zero values:
[1,3,12,_,_]
Fill remaining:
[1,3,12,0,0]
Algorithm
- Maintain an index for placing non-zero values.
- Traverse the array.
- Copy non-zero values forward.
- Fill remaining positions with zero.
Java Program
import java.util.Arrays;
public class MoveZerosOptimized {
public static void moveZeros(
int[] numbers) {
int index = 0;
for (int number : numbers) {
if (number != 0) {
numbers[index++] = number;
}
}
while (index < numbers.length) {
numbers[index++] = 0;
}
}
public static void main(String[] args) {
int[] numbers =
{0,1,0,3,12};
moveZeros(numbers);
System.out.println(
Arrays.toString(numbers));
}
}
Output
[1,3,12,0,0]
Step-by-Step Explanation
Input:
[0,1,0,3,12]
Initial:
index = 0
Read:
0
Skip.
Read:
1
Place:
numbers[0] = 1
Array:
[1,1,0,3,12]
Read:
3
Place:
numbers[1] = 3
Array:
[1,3,0,3,12]
Read:
12
Place:
numbers[2] = 12
Array:
[1,3,12,3,12]
Fill remaining:
[1,3,12,0,0]
Complexity Analysis
Time:
O(n)
Space:
O(1)
Advantages
- Fewer write operations than swap approach.
- Maintains order.
- In-place solution.
- Production friendly.
Drawbacks
- Slightly less intuitive.
- Requires overwriting logic.
Approach 4 — Using Java Streams
Java Streams provide a functional programming approach.
The idea:
- Filter non-zero elements.
- Add zeros at the end.
Java Program
import java.util.Arrays;
import java.util.stream.IntStream;
public class MoveZerosStreams {
public static int[] moveZeros(
int[] numbers) {
long zeroCount =
Arrays.stream(numbers)
.filter(n -> n == 0)
.count();
int[] result =
IntStream.concat(
Arrays.stream(numbers)
.filter(n -> n != 0),
IntStream.generate(() -> 0)
.limit(zeroCount)
)
.toArray();
return result;
}
public static void main(String[] args) {
int[] numbers =
{0,1,0,3,12};
System.out.println(
Arrays.toString(
moveZeros(numbers)));
}
}
Output
[1,3,12,0,0]
Step-by-Step Explanation
Original:
[0,1,0,3,12]
Filter non-zero:
[1,3,12]
Count zeros:
2
Generate:
[0,0]
Combine:
[1,3,12,0,0]
Complexity Analysis
Time:
O(n)
Space:
O(n)
Advantages
- Clean functional style.
- Easy to understand.
- Useful in stream-based processing.
Drawbacks
- Creates a new array.
- Not in-place.
- More memory usage.
Approach 5 — Partition Approach
Moving zeros to the end is similar to partitioning an array.
The idea is:
Separate:
Non-zero values
and
Zero values
Partition Concept
Example:
Input:
[0,5,0,2,8]
Partition:
Left side:
[5,2,8]
Right side:
[0,0]
Result:
[5,2,8,0,0]
Java Program
import java.util.Arrays;
public class MoveZerosPartition {
public static void moveZeros(
int[] numbers) {
int left = 0;
for (int right = 0;
right < numbers.length;
right++) {
if (numbers[right] != 0) {
int temp =
numbers[left];
numbers[left] =
numbers[right];
numbers[right] =
temp;
left++;
}
}
}
public static void main(String[] args) {
int[] numbers =
{0,5,0,2,8};
moveZeros(numbers);
System.out.println(
Arrays.toString(numbers));
}
}
Output
[5,2,8,0,0]
In-Place vs Extra Space
| Approach | In-Place | Space |
|---|---|---|
| Extra Array | ❌ | O(n) |
| Two Pointer Swap | ✅ | O(1) |
| Optimized Two Pointer | ✅ | O(1) |
| Streams | ❌ | O(n) |
| Partition | ✅ | O(1) |
Primitive vs Object Arrays
Primitive Array
Example:
int[]
Advantages:
- Faster performance.
- Less memory.
- No boxing overhead.
Recommended for:
Large numeric arrays
Object Array
Example:
Integer[]
Advantages:
- Works with Collections.
- Supports generics.
Example:
List<Integer>
Comparison of All Approaches
| Approach | Time | Space | Stable | Recommended |
|---|---|---|---|---|
| Extra Array | O(n) | O(n) | Yes | Learning |
| Two Pointer Swap | O(n) | O(1) | Yes | Interview |
| Optimized Two Pointer | O(n) | O(1) | Yes | Production |
| Streams | O(n) | O(n) | Yes | Functional Style |
| Partition | O(n) | O(1) | Yes | Low Memory |
Common Interview Mistakes
Mistake 1
Using nested loops.
Example:
for every zero
shift all elements
Complexity:
O(n²)
Avoid.
Mistake 2
Changing order of elements.
Wrong:
[0,1,0,3,12]
↓
[12,1,3,0,0]
Correct:
[1,3,12,0,0]
Mistake 3
Creating unnecessary arrays.
If interviewer asks:
Solve in-place
Do not use:
new int[n]
Mistake 4
Not handling all-zero arrays.
Example:
[0,0,0]
Output:
[0,0,0]
Mistake 5
Ignoring negative numbers.
Example:
Input:
[0,-1,2,0,-5]
Output:
[-1,2,-5,0,0]
Edge Cases
| Input | Output |
|---|---|
[] |
[] |
[0] |
[0] |
[1,2,3] |
Same array |
[0,0,1] |
[1,0,0] |
[-1,0,2] |
[-1,2,0] |
Interview Follow-up Questions
Q1. Move zeros to beginning.
Q2. Move negative numbers to one side.
Q3. Remove duplicates from sorted array.
Q4. Partition array around pivot.
Q5. Move all even numbers first.
Q6. Solve without changing order.
Q7. Solve with minimum swaps.
Q8. What is the optimal approach?
Related Problems
- Remove Duplicates from Array
- Partition Array
- Sort Colors
- Move Negative Numbers
- Remove Element
- Two Pointer Problems
- Array Rotation
Key Takeaways
- Moving zeros is a classic two pointer problem.
- The best interview solution is:
Two Pointer
Complexity:
Time: O(n)
Space: O(1)
- Maintain relative order of non-zero elements.
- Avoid unnecessary shifting operations.
- Choose approach based on:
- Memory constraints
- Readability
- Performance requirements
Frequently Asked Interview Questions
Q1. What is the optimal solution?
Optimized two pointer approach.
Time: O(n)
Space: O(1)
Q2. Why use two pointers?
Because we can rearrange elements in one pass without extra memory.
Q3. Is order preserved?
Yes.
The relative order of non-zero elements remains unchanged.
Q4. Can this be done without modifying the array?
Yes.
Use:
- Extra array
- Streams
Q5. Production recommendation?
For most applications:
In-place two pointer approach
because it provides:
- Best memory usage
- Linear performance
- Simple implementation
Interview Tip
When asked:
"Move all zeros to the end of an array."
Clarify:
- Should order be preserved?
- Can the array be modified?
- Is extra memory allowed?
Then explain:
- Brute Force
- Extra Array
- Two Pointer Swap
- Optimized Two Pointer
- Stream Approach
The ability to explain why O(n) time and O(1) space is optimal demonstrates strong understanding of Java arrays, memory management, and algorithm design.