In-Place Tricks: A Slow and a Fast Pointer

Same direction, different speeds

Another kind of two pointers: both start on the left. The fast pointer looks at every item; the slow pointer marks where the next “keeper” should go.

Think of it like this: Tidying a bookshelf: your right hand picks up each book (fast); your left hand marks the next empty spot for a book you decide to keep (slow).

Remove duplicates from a sorted list

def remove_duplicates(nums):
    if not nums:
        return 0
    slow = 0
    for fast in range(1, len(nums)):
        if nums[fast] != nums[slow]:
            slow += 1
            nums[slow] = nums[fast]
    return slow + 1              # how many unique values

data = [1, 1, 2, 3, 3, 3, 7]
k = remove_duplicates(data)
print(k, data[:k])

Output

4 [1, 2, 3, 7]

Move all zeros to the end

def move_zeros(nums):
    slow = 0
    for fast in range(len(nums)):
        if nums[fast] != 0:
            nums[slow], nums[fast] = nums[fast], nums[slow]
            slow += 1
    return nums

print(move_zeros([0, 5, 0, 3, 12]))

Output

[5, 3, 12, 0, 0]

Both run in O(n) time with O(1) extra space – no new list is created.

Common mistake: Don't remove items from a list while looping over it with for x in nums – Python skips items. Use the slow/fast pattern or build a new list instead.

HOME LABS COMMUNITY DASHBOARD