Time to learn one of the most elegant tricks in array manipulation: the read/write pointer technique. This is the baby version of a pattern you'll use over and over again. 🍼➡️💪
Picture a bouncer at a club. There's a line of people, but some don't have tickets. The bouncer's job: remove everyone without a ticket and shuffle the remaining people forward so there are no gaps. No extra line allowed — everything happens in-place. 🚪🕺
The Two-Pointer Setup:
Let's trace through removing 3 from [3, 2, 2, 3]:
⏱ Time Complexity: O(n) — The read pointer visits each element exactly once.
💾 Space Complexity: O(1) — We're not creating a new array. Everything happens in-place with just two pointer variables. The bouncer doesn't need a second club! 🏗️
🔮 Why this matters: The next problem is Move Zeroes — which is basically this SAME technique, but instead of removing elements, you're partitioning them (non-zeroes to the front, zeroes to the back). If you get the read/write pointer down here, Move Zeroes will feel like a remix of a song you already know. 🎶
def remove_element(nums, val):
write = 0
for read in range(len(nums)):
if nums[read] != val:
nums[write] = nums[read]
write += 1
return write
nums1 = [3, 2, 2, 3]
k = remove_element(nums1, 3)
print(f"New length: {k}, Array: {nums1[:k]}")
nums2 = [0, 1, 2, 2, 3, 0, 4, 2]
k = remove_element(nums2, 2)
print(f"New length: {k}, Array: {nums2[:k]}")
nums3 = [1, 1, 1]
k = remove_element(nums3, 1)
print(f"New length: {k}, Array: {nums3[:k]}")