Move Zeroes
Given an integer array nums, move all 0s to the end of it while maintaining the relative order of the non-zero elements. Note that you must do this in-place without making a copy of the array.
- 1 <= nums.length <= 10^4
- -2^3^1 <= nums[i] <= 2^3^1 - 1
- Must be done in-place without making a copy of the array
- Minimize the total number of operations
nums = [0,1,0,3,12][1,3,12,0,0]nums = [0][0]nums = [1,2,3][1,2,3]Our goal is to take a list of numbers and push all the zeroes straight to the back, while keeping all the normal numbers in their original order.
The naive way is to just create a brand new list. You pull out all the normal numbers, put them in the new list, and pack zeros at the end. This is extremely easy, but it requires allocating an entire second list, which ruins our goal of modifying the list natively.
non_zeros = [x for x in nums if x != 0]
zeros = [0] * (len(nums) - len(non_zeros))
nums[:] = non_zeros + zeros # Uses extra memoryMoving items to the end of a list without freezing up extra memory is a textbook scenario for the Two-Pointer Pattern. This pattern is critically important because it allows us to do "in-place" modifications without using a backup list. We can rearrange the numbers directly inside the original list using two tracking roles:
- Writer (Slow): Keeps track of where the next real number should be placed.
- Scout (Fast): Runs ahead to find real numbers.
The Scout sweeps across the array from left to right. Every time it finds a normal number (not a zero), we swap it with the Writer's position. Then, we bump the Writer forward by one. By constantly swapping the real numbers to the front, all the zeros naturally get pushed out to the back.
writer = 0
for scout in range(len(nums)):
if nums[scout] != 0:
nums[writer], nums[scout] = nums[scout], nums[writer]
writer += 1Two-Pointer Swap
In-Place Array Partitioning
In-Place Efficiency
We use two pointers to partition the array. The anchor pointer tracks the boundary where the next non-zero element should be placed, while the scan pointer explores new values.
Optimal Operation Count
By swapping non-zeroes with zeroes, we eliminate the need for a second pass to fill remaining slots. This achieves O(N) time with only O(1) auxiliary space.