Loading problems...
TL;DR: Use a "write pointer" to consolidate all non-zero elements at the beginning of the array, then fill the remaining positions with zeros (or swap elements to achieve the same effect in one pass).
The LeetCode 283 problem, titled Move Zeroes, asks us to manipulate an integer array nums. The objective is to shift all occurrences of 0 to the end of the array. Crucially, the relative order of the non-zero elements must remain unchanged. This operation must be performed in-place, meaning we cannot allocate a new array to store the result; we must modify the input array directly with extra space.
A naive approach to solving Move Zeroes usually involves prioritizing the logic over the space constraints. One might attempt to create a temporary array to store the result.
result, of the same size as nums.nums. If an element is non-zero, append it to result.result with zeros after the loop.result back into nums.Pseudo-code:
textfunction moveZeroesNaive(nums): tempArray = [] zeroCount = 0 for x in nums: if x != 0: tempArray.append(x) else: zeroCount++ while zeroCount > 0: tempArray.append(0) zeroCount-- nums = tempArray // Copy back
Why this fails: While this solution produces the correct output, it violates the problem's strict constraint: "do this in-place without making a copy of the array."
Another brute force variation involves using nested loops (similar to Bubble Sort) to "bubble" zeros to the end one by one. This satisfies the space constraint but results in time complexity, which is inefficient for large inputs ().
The key intuition for the optimal LeetCode 283 Solution is to decouple the act of finding a non-zero element from the act of placing it.
We can maintain a pointer, let's call it write_pointer, that indicates the index where the next non-zero element belongs. As we iterate through the array with a read_pointer, every time we encounter a non-zero element, we know it belongs at the write_pointer's position.
The Invariant:
At any step of the iteration, the subarray nums[0...write_pointer-1] contains all processed non-zero elements in their correct relative order.
By swapping the non-zero element found at read_pointer with the element at write_pointer, we achieve two things simultaneously:
write_pointer was pointing to one) or the placeholder moves toward the end.Visual Description:
Imagine the array is divided into two logical regions by the write_pointer:
As the read_pointer scans right, the write_pointer only advances when a non-zero is locked into the Stable Region. If the array has no zeros, both pointers move together. If zeros exist, the read_pointer moves ahead, creating a gap between the two pointers that represents the accumulated zeros.

Let's trace nums = [0, 1, 0, 3, 12]
write_pointer = 0, read_pointer = 0.nums[0] is 0.
write_pointer stays at 0.nums[1] is 1.
1 != 0).nums[write_pointer] (index 0) and nums[read_pointer] (index 1).[1, 0, 0, 3, 12].write_pointer to 1.nums[2] is 0.
write_pointer stays at 1.nums[3] is 3.
3 != 0).nums[1] (value 0) and nums[3] (value 3).[1, 3, 0, 0, 12].write_pointer to 2.nums[4] is 12.
12 != 0).nums[2] (value 0) and nums[4] (value 12).[1, 3, 12, 0, 0].write_pointer to 3.[1, 3, 12, 0, 0].The algorithm is correct based on the Loop Invariant:
At the start of each iteration i, the subarray nums[0...write_pointer-1] consists of all non-zero elements found in nums[0...i-1], in their original relative order.
write_pointer is 0. The subarray is empty, vacuously satisfying the property.nums[i] is non-zero, we move it to nums[write_pointer]. Since write_pointer is the first available slot after the previously processed non-zeros, the relative order is preserved. We then increment write_pointer to maintain the invariant.i reaches , nums[0...write_pointer-1] contains all non-zeros from the entire array. The remaining elements (from write_pointer to ) must be zeros because every time we found a non-zero, we moved it out of that area (via swap) or it was already in the correct place.cppclass Solution { public: void moveZeroes(vector<int>& nums) { int writePtr = 0; // Iterate through the array with a read pointer (i) for (int readPtr = 0; readPtr < nums.size(); readPtr++) { // If the current element is non-zero if (nums[readPtr] != 0) { // Swap the non-zero element to the write position // This handles both moving non-zeros to front // and zeros to back simultaneously. swap(nums[writePtr], nums[readPtr]); writePtr++; } } } };
javaclass Solution { public void moveZeroes(int[] nums) { int writePtr = 0; // Iterate through the array for (int readPtr = 0; readPtr < nums.length; readPtr++) { // If we find a non-zero element if (nums[readPtr] != 0) { // Swap the current element with the element at writePtr int temp = nums[writePtr]; nums[writePtr] = nums[readPtr]; nums[readPtr] = temp; // Advance the write pointer writePtr++; } } } }
pythonclass Solution: def moveZeroes(self, nums: List[int]) -> None: """ Do not return anything, modify nums in-place instead. """ write_ptr = 0 for read_ptr in range(len(nums)): if nums[read_ptr] != 0: # Pythonic swap to move non-zero to the front nums[write_ptr], nums[read_ptr] = nums[read_ptr], nums[write_ptr] write_ptr += 1
Time Complexity: We perform a single pass through the array of length . Inside the loop, we perform constant time operations (comparison, swap, increment). Thus, the total time is linear.
Space Complexity:
We only use two integer variables (write_pointer and the loop iterator read_pointer) for storage. No auxiliary data structures are created. This strictly satisfies the in-place requirement.
The Two Pointers - In-place Array Modification pattern is a fundamental technique for array manipulation. Understanding the logic of write_pointer vs read_pointer enables you to solve several related interview questions efficiently:
Why does my solution get a Time Limit Exceeded (TLE)?
remove() inside a for loop) or bubble sort logic.remove() or shifting elements in an array is an operation. Doing this inside a loop results in complexity.Why is my output correct locally but rejected by LeetCode?
nums in-place.void. The judge checks the memory address of the input array nums.Why are my zeros not at the end?
nums[write] = nums[read]) but forget to fill the remaining indices (from write to end) with 0, the end of the array will contain stale data (duplicates of the non-zeros).