Move Zeroes and Remove Element (Stable Partition)
Pattern: Two Pointers (Same Direction) · Difficulty: Easy · Asked at: Meta, Bloomberg, Apple
Classic version: LeetCode 283 · LeetCode 27
Problem
move_zeroes(nums): move all0s to the end in place, keeping the relative order of non-zero elements. Return nothing.remove_value(nums, val): remove every occurrence ofvalin place and return the new lengthn;nums[:n]must keep the remaining elements in their original order.
Examples
nums = [0, 1, 0, 3, 12]; move_zeroes(nums) → nums == [1, 3, 12, 0, 0]
nums = [3, 2, 2, 3]; remove_value(nums, 3) → 2, nums[:2] == [2, 2]
Starter code
def move_zeroes(nums: list[int]) -> None:
pass
def remove_value(nums: list[int], val: int) -> int:
pass
Hints
Hint 1
Both are the same loop: a write pointer for kept elements and a read pointer over everything.
Hint 2
For move_zeroes, swapping nums[write] and nums[read] (instead of overwriting) leaves the zeroes at the end automatically.
Where this shows up in data engineering
Stable partitioning is the in-memory core of filter pushdown and of splitting a batch into valid/quarantine rows while keeping order (important when order encodes event time).
Solution
def move_zeroes(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
def remove_value(nums: list[int], val: int) -> int:
write = 0
for x in nums:
if x != val:
nums[write] = x
write += 1
return write
Tests
Your solution should pass these:
a = [0, 1, 0, 3, 12]
move_zeroes(a)
assert a == [1, 3, 12, 0, 0]
b = [0]
move_zeroes(b)
assert b == [0]
c = [1, 2, 3]
move_zeroes(c)
assert c == [1, 2, 3]
d = [3, 2, 2, 3]
assert remove_value(d, 3) == 2 and d[:2] == [2, 2]
e = [0, 1, 2, 2, 3, 0, 4, 2]
assert remove_value(e, 2) == 5 and e[:5] == [0, 1, 3, 0, 4]
Explanation
One template, two uses: nums[:write] holds the kept elements in order. Overwriting is enough when the tail doesn’t matter (remove_value); swapping keeps every element, so the rejected ones collect at the end (move_zeroes).
Complexity: O(n) time, O(1) space. Minimum writes: the swap version does a swap even when write == read; guard with if write != read if writes are expensive (e.g. flash storage).
Unstable alternative: when order doesn’t matter, swap the rejected element with the last element and shrink the array. Fewer writes when rejects are rare.
Follow-up questions
Partition into three groups in one pass (e.g. negative, zero, positive).
Dutch national flag: pointers lo, mid, hi; swap negatives to lo, positives to hi, advance mid over zeroes. One pass, O(1) space, but not stable.