Move Zeroes
Move all zeroes in an array to the end in place, keeping the relative order of the non-zero elements.
Open on LeetCode ↗Intuition
The common instinct is to swap on every non-zero element. That is correct, but it does needless writes — a swap is two stores where one would do, and when the array has no zeroes at all you end up swapping every element with itself. Worse is the variation people reach for when they are trying to be clever: swap the zero at the front with a non-zero found from the back. That version passes the 'zeroes at the end' half of the test and silently violates the other half, because it REORDERS the non-zero elements, which the problem explicitly forbids. The fix is to stop thinking in swaps. Keep a write pointer w and scan with k; whenever nums[k] is non-zero, overwrite nums[w] with it and advance w. Because you scan strictly left to right and only ever copy forward, the non-zeroes land in exactly the order they appeared — order is preserved by construction, not by care. The invariant is that nums[0:w] always holds every non-zero seen so far, in order; after the scan, fill from w to the end with zeroes.
Approach
One write pointer, one scanner
w marks the next slot that should receive a non-zero value; k walks the whole array. Everything left of w is finished and correct, everything from w up to k is stale data that will be overwritten or zeroed later. Framing it this way removes the swap entirely, because you never need to preserve what is sitting at nums[w] — it has either already been copied forward or it is a zero you were going to discard anyway.
Copy non-zeroes forward
For each k, if nums[k] is non-zero, assign nums[w] = nums[k] and increment w. Zeroes are simply skipped, which leaves w behind and lets the next non-zero close the gap. Since w never exceeds k, the write can never clobber a value that has not been read yet — that is what makes the single-pass in-place version safe.
Pad the tail with zeroes
After the scan, w equals the count of non-zero elements, and everything from w to the end is leftover junk from the original array. Write zeroes over that range. This second pass is what makes the whole thing O(n) with two cheap sweeps instead of one clever but fragile one, and it keeps the total number of writes at most n.
Solution & live demo
Edge cases
The first pass never writes and w stays 0, so the padding loop rewrites the whole array with zeroes — already correct, just redundant.
w tracks k exactly, so every write is nums[k] = nums[k], and the padding loop does not run. The array is unchanged.
Either it is non-zero and copied to slot 0, or it is a zero and the pad loop writes 0 back. Both are no-ops in effect.
The non-zeroes copy onto themselves and the tail is re-zeroed. Correct, and it costs nothing extra beyond the writes.