1. Opposite Ends (The Squeeze)
Use this for sorted arrays where you need to find a pair (e.g., Two Sum II, 3Sum, Reverse String).
public void oppositeEnds(int[] nums) {
int left = 0, right = nums.length - 1;
while (left < right) {
int sum = nums[left] + nums[right];
if (sum == target) {
// Found result!
return;
} else if (sum < target) {
left++; // Need a larger value
} else {
right--; // Need a smaller value
}
}
}
2. Fast & Slow (The Tortoise and Hare)
Use this for Linked Lists or cyclic structures to find middle, detect cycles, or find k-th elements.
public void tortoiseAndHare(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next; // Move 1 step
fast = fast.next.next; // Move 2 steps
if (slow == fast) {
// Cycle detected!
}
}
}
3. Multiple Inputs (The Parallel Scan)
Use this to merge or compare two different sorted arrays (e.g., Merge Sorted Array, Intersection of Lists).
public void parallelScan(int[] arr1, int[] arr2) {
int i = 0, j = 0;
while (i < arr1.length && j < arr2.length) {
if (arr1[i] < arr2[j]) {
i++;
} else if (arr1[i] > arr2[j]) {
j++;
} else {
// Match found!
i++; j++;
}
}
}
4. Interview Discussion: The "Aha!" Moment
Whenever you see a problem with Sorted Inputs or a need to reduce an $O(N^2)$ nested loop to $O(N)$, Two Pointers is your first line of defense. It leverages the order of the data to eliminate redundant comparisons.