Shift every 0 to the end of the array in place while keeping the non-zeroes in their original order. A slow write pointer packs the non-zeroes to the front; the zeroes fall out the back for free.
Push every 0 to the back of nums, in place, without disturbing the order of the non-zero values. Example: nums=[0,1,0,3,12] becomes [1,3,12,0,0] — the non-zeroes 1,3,12 stay in order and the two zeroes drift to the end.
slow pointer at the next empty write slot. Sweep fast across the array; every time it lands on a non-zero, swap that value into slow and bump slow. Once the keepers are packed at the front in order, the tail is automatically all zeroes.slow=0 and fast=0. Both walk left→right; slow never outruns fast.nums[fast]===0, do nothing — why: leave the hole so a later non-zero can overwrite it.nums[fast]!==0, swap it into nums[slow] then slow++ — why: this places the next keeper at the front and sends any trapped zero forward.fast reaches the end, the first slow cells are the non-zeroes in order and everything after is zeroes.nums[slow]=nums[fast] for non-zeroes and then fill the tail with zeroes in a second pass. That works, but you must then zero out indices slow…n-1 — forget that and stale values linger. The swap version avoids the second pass because each swap carries a zero backward.The two pointers are the only extra storage; all rearrangement happens inside the original array via swaps. Each element is examined once, so it is a single linear pass with at most n swaps.
slow marks the next slot for a non-zero; fastscans left → right.1function moveZeroes(nums: number[]): void {2▶ let slow = 0; // next slot for a non-zero3▶ for (let fast = 0; fast < nums.length; fast++) {4 if (nums[fast] !== 0) { // found a non-zero to keep5 [nums[slow], nums[fast]] = [nums[fast], nums[slow]];6 slow++; // advance the write pointer7 }8 }9}
function moveZeroes(nums: number[]): void {
let slow = 0; // next slot for a non-zero
for (let fast = 0; fast < nums.length; fast++) {
if (nums[fast] !== 0) { // found a non-zero to keep
[nums[slow], nums[fast]] = [nums[fast], nums[slow]];
slow++; // advance the write pointer
}
}
}slow tracks where the next non-zero should land. Everything before slow is already a packed, ordered non-zero.fast visits every index once, looking for the next value worth keeping.nums[fast] is non-zero, swap it into nums[slow]. If slow===fast the swap is a no-op; otherwise nums[slow] held a zero, which now rides forward to index fast. Then slow++ claims the next slot.nums[fast]===0 the loop simply moves on, slow unchanged — the zero stays put as a hole to be overwritten or pushed back by a later swap.slow===fast (the element is already in place); only swap when slow<fast.!== 0 test with !== k — this is exactly Remove Element.function moveZeroes(nums: number[]): void {
let slow = 0; // next slot for a non-zero
for (let fast = 0; fast < nums.length; fast++) {
if (nums[fast] !== 0) { // found a non-zero to keep
[nums[slow], nums[fast]] = [nums[fast], nums[slow]];
slow++; // advance the write pointer
}
}
}Copy each non-zero forward with the same slow cursor, then make a second pass filling slow…n-1 with zeroes.
function moveZeroes(nums: number[]): void {
let slow = 0;
for (let fast = 0; fast < nums.length; fast++) {
if (nums[fast] !== 0) nums[slow++] = nums[fast];
}
while (slow < nums.length) nums[slow++] = 0;
}The most obvious idea — and the one to avoid because it allocates.
function moveZeroes(nums: number[]): void {
const out: number[] = [];
for (const x of nums) if (x !== 0) out.push(x);
while (out.length < nums.length) out.push(0);
for (let i = 0; i < nums.length; i++) nums[i] = out[i];
}| "in place, preserve order" | slow write pointer + swap |
| compact items to the front | swap into slow, slow++ |
| move/remove a target value | predicate on nums[fast] |
| partition by a condition | two pointers, same direction |
let slow = 0;
for (let fast = 0; fast < nums.length; fast++) {
if (nums[fast] !== 0) {
[nums[slow], nums[fast]] = [nums[fast], nums[slow]];
slow++;
}
}