Move Zeroes
Given an integer array nums, move all 0s to the end while keeping the relative order of
the non-zero elements. You must do this in place without making a copy of the array; the
function returns nothing and mutates nums directly.
Examples
Input: nums = [0,1,0,3,12] -> [1,3,12,0,0]
Input: nums = [0] -> [0]
Input: nums = [1,2,3] -> [1,2,3]
Constraints
1 <= len(nums) <= 10^4-2^31 <= nums[i] <= 2^31 - 1
Solution
Approach — slow/fast pointers with a swap
The requirement to keep the non-zero elements in their original relative order (stability) rules out sorting or two-ends swapping. The clean stable technique is a slow/fast pointer pair.
fast scans the array. slow marks the next slot where a non-zero value belongs. Every time
fast finds a non-zero, we swap it into nums[slow] and advance slow. Non-zeros get packed
toward the front in order, and the zeros they displace bubble toward the back automatically.
Solution
def move_zeroes(nums: list[int]) -> None:
slow = 0 # next slot for a non-zero value
for fast in range(len(nums)):
if nums[fast] != 0:
nums[slow], nums[fast] = nums[fast], nums[slow]
slow += 1
Explanation
- Why order is preserved:
fastvisits elements left to right, and each non-zero is placed at the next availableslowslot in that same order — so their relative sequence never changes. The swap sends whatever was atslow(always a0once we've fallen behind) out tofast's position, pushing zeros rightward. - Why the swap is harmless when there are no leading zeros: while
slow == fast(no zeros seen yet), the swap exchanges an element with itself — a no-op — so the algorithm costs nothing extra on already-packed prefixes. - The invariant: at every step,
nums[0..slow)holds all non-zeros seen so far in order, andnums[slow..fast)holds only zeros. When the scan ends, all non-zeros are packed at the front and all zeros trail behind.
Complexity
- Time:
O(n)— one pass, each swap isO(1). - Space:
O(1)— fully in place, just two index variables.
Interview tips
If you don't need to minimize writes, an alternative is: copy all non-zeros forward with
slow, then fill the remainder with zeros — same complexity, marginally more writes but
sometimes clearer. The swap version minimizes writes (it only touches elements that actually
move). Interviewers may ask you to prove stability; point to the left-to-right scan placing
each non-zero at the next slot as the argument.