Given an integer array nums, move all 0's to the end of it while maintaining the relative order of the non-zero elements. You must do this in-place without making a copy of the array and aim to minimize the total number of operations (assignments).
Constraints:
1 <= nums.length <= 10^4-2^31 <= nums[i] <= 2^31 - 1
Example:
Input: nums = [0,1,0,3,12]
Output: [1,3,12,0,0]
Solution
Approach: Two Pointers (Two-Pass)
This problem can be efficiently solved using a two-pointer technique over two passes.
- Initialize a
write_pointer: This pointer will keep track of the position where the next non-zero element should be placed. Initialize it to0. - First Pass (Move Non-Zeroes):
- Iterate through the array with a
read_pointerfrom the beginning to the end. - If
nums[read_pointer]is not zero:- Place
nums[read_pointer]atnums[write_pointer]. - Increment
write_pointer.
- Place
- After this pass, all non-zero elements will be at the beginning of the array, in their original relative order. The
write_pointerwill be positioned at the first index where a zero should be placed.
- Iterate through the array with a
- Second Pass (Fill Remaining with Zeroes):
- Iterate from the
write_pointerto the end of the array. - Set each element
nums[i]in this range to0.
- Iterate from the
This approach ensures that the relative order of non-zero elements is preserved and minimizes the total number of assignments to N (where N is the length of the array), making it optimal for the specified constraints.
def moveZeroes(nums: list[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
write_pointer = 0
# First pass: Move all non-zero elements to the beginning of the array
for read_pointer in range(len(nums)):
if nums[read_pointer] != 0:
nums[write_pointer] = nums[read_pointer]
write_pointer += 1
# Second pass: Fill the rest of the array with zeros
for i in range(write_pointer, len(nums)):
nums[i] = 0
