Both pointers start at the beginning. One pointer (fast) explores ahead, while the other (slow) marks a position. This pattern is perfect for in-place array modifications.
Template
The pattern: The slow pointer marks where the next valid element should go. The fast pointer scans through the array finding valid elements. When a valid element is found, it's placed at the slow position.
Remove Duplicates from Sorted Array
Remove duplicates in-place from a sorted array and return the new length.
Key insight: In a sorted array, duplicates are adjacent. The slow pointer marks the end of the unique portion. When we find a new unique element, we extend that portion.
Move Zeroes to End
Move all zeroes to the end while maintaining the relative order of non-zero elements.
Why swap instead of overwrite? Swapping preserves the zeroes and moves them to the back naturally. We could also overwrite and fill zeroes at the end, but swapping is elegant.
Remove Element
Remove all instances of a value in-place and return the new length.
Remove Duplicates II (Allow 2 copies)
Allow at most 2 duplicates in a sorted array.
Generalization: To allow at most k duplicates, compare with the element k positions back: nums[fast] != nums[slow - k]
Merge Two Sorted Arrays
Merge nums2 into nums1, which has enough space at the end.
Why work backwards? Working from the end means we never overwrite elements we still need to process. The largest elements get placed first.
Partition Array
Partition an array around a pivot (used in quicksort).
Sort Colors (Dutch National Flag)
Sort an array with three distinct values (0, 1, 2) in-place using three pointers.
Three regions: Elements before low are 0s, between low and mid are 1s, after high are 2s. The mid pointer processes unknown elements.