Last Updated: March 27, 2026
At first glance, this looks trivial: just separate zeroes from non-zeroes. But there are two constraints that make it interesting. First, you need to preserve the relative order of non-zero elements. Second, you must do it in-place, meaning no new array.
The key observation is this: if you can figure out where each non-zero element should end up, the zeroes will naturally fill the remaining positions at the end. So the real question becomes: how do we efficiently place non-zero elements in their correct positions without disturbing their order?
1 <= nums.length <= 10^4 → With n up to 10,000, O(n^2) would mean 100 million operations, which is tight but passable. O(n) is clearly preferred.-2^31 <= nums[i] <= 2^31 - 1 → Full 32-bit integer range. Values can be negative, so "non-zero" includes negative numbers. Don't confuse "non-zero" with "positive."in-place → The problem explicitly forbids creating a copy of the array. Any solution using O(n) extra space technically violates the constraint.The most straightforward way to think about this: collect all the non-zero elements in order, then fill the rest with zeroes. If we ignore the in-place constraint for a moment, we can use an extra array to build the result, then copy it back.
This approach won't satisfy the follow-up requirement, but it's a clean starting point that makes the logic crystal clear.
result of the same size as nums.nums. For each non-zero element, place it at the next available position in result.result are already zero (default values).result back into nums.Input:
After the first pass (collect non-zeroes into result):
Finally, we copy result back into nums:
This approach works correctly but uses extra space.
What if we placed non-zero elements directly into their final positions within the original array?
We can use a single pointer insertPos to track where the next non-zero element should go. As we scan through the array, every time we find a non-zero element, we swap it into the insertPos position and advance the pointer.
The insertPos pointer is always at or behind the current scanning index i. Everything before insertPos is a correctly placed non-zero element. Everything between insertPos and i is a zero (or will become one after the swap).
So the swap effectively moves a non-zero forward and a zero backward, which is exactly what we want.
insertPos = 0 to track the next position for a non-zero element.i from 0 to n - 1.nums[i] is not zero, swap nums[i] with nums[insertPos], then increment insertPos.insertPos, temp). No additional data structures.Approach 2 always performs a swap when it finds a non-zero element, even when i == insertPos, meaning the element is already where it belongs. In an array like [1, 2, 3, 0, 0], the first three iterations all do unnecessary self-swaps.
The fix is simple: only swap when i != insertPos. This skips redundant operations when non-zero elements are already in place. It's the same algorithm with a small guard condition, but in arrays with few zeroes (or zeroes concentrated at the end), this can significantly reduce the number of write operations.
insertPos = 0.i.nums[i] is not zero:i != insertPos, swap nums[i] with nums[insertPos].insertPos.