The idea in one pictureCore idea
Instead of checking every pair with two loops, you keep two positions, look at the elements under them, and use what you see to decide which one to move. Every step moves at least one pointer, so the whole walk takes one pass.
There are three ways the pointers can move. Almost every two-pointer problem is one of them:
Opposite endssorted
Start at both ends and walk toward each other. Pair sums, palindromes, container problems.
Same directionread / write
One pointer reads ahead, the other marks where to write. Removing duplicates, partitioning.
Fast and slowspeeds
One pointer moves one step, the other two. Cycle detection, finding the middle of a list.
Pattern 1: Opposite endsPattern
Two pointers start at opposite ends of a sorted array and move toward each other. Because the array is sorted, the sum tells you which pointer to move: too big means the right value is too large, too small means the left value is too small.
Two Sum II, target = 15
function twoSumII(nums: number[], target: number): [number, number] {
let left = 0, right = nums.length - 1;
while (left < right) {
const sum = nums[left] + nums[right];
if (sum === target) return [left + 1, right + 1];
else if (sum < target) left++;
else right--;
}
return [-1, -1];
}Pattern 2: Same directionPattern
Both pointers move the same way. One pointer (read) leads and looks at every element; the other (write) follows and marks where the next element you want to keep should go. It is used for removing duplicates and partitioning in place.
Remove duplicates from [1, 1, 2, 2, 3]
function removeDuplicates(nums: number[]): number {
let write = 1;
for (let read = 1; read < nums.length; read++) {
if (nums[read] !== nums[read - 1]) {
nums[write] = nums[read];
write++;
}
}
return write;
}Pattern 3: Fast and slow pointersPattern
One pointer moves one step at a time, the other moves two. It is used for cycle detection (Floyd's algorithm) and for finding the middle of a linked list: when the fast pointer reaches the end, the slow one is halfway.
function hasCycle(head: ListNode | null): boolean {
let slow = head, fast = head;
while (fast && fast.next) {
slow = slow!.next;
fast = fast.next.next;
if (slow === fast) return true;
}
return false;
}When to use two pointersWhen to use
| If the problem says… | Try | Why |
|---|---|---|
| “sorted array”, “pair with sum” | Opposite ends | The sum tells you which side to shrink. |
| “in place”, “remove”, “O(1) extra space” | Same direction | read scans, write keeps what survives. |
| “linked list”, “cycle”, “middle” | Fast and slow | Different speeds reveal loops and midpoints. |
Common mistakesPitfalls
How to explain it in the interviewIn the interview
Interviewers want to hear why moving a pointer is safe, not just that you moved it. Say the rule out loud:
Frequently asked questionsFAQ
When should I use two pointers instead of a hash map?
Use two pointers when the input is sorted or when the problem only compares elements at two positions, because both pointers move in a single pass. A hash map is better when the array is unsorted and you need lookups of previously seen values, such as finding a pair that sums to a target. Two pointers uses O(1) extra space; a hash map uses O(n).
Does the two pointers technique require the input to be sorted?
Only the opposite ends pattern requires sorted input, because the algorithm decides which pointer to move by comparing the current sum against the target. The same direction and fast/slow patterns do not need sorted data, since they compare neighbors or advance at different speeds. Sort first when the problem allows O(n log n) preprocessing and then a linear scan.
How does Floyd's cycle detection algorithm find a cycle in a linked list?
Floyd's algorithm moves one pointer one node at a time and a second pointer two nodes at a time. If the list has a cycle, the fast pointer keeps lapsing the slow one and they eventually reference the same node, which proves a cycle exists. If the fast pointer reaches the end of the list first, there is no cycle. Both the time and extra space cost O(1).

Now explain two pointers to me out loud
I'll give you interview problems and ask follow-ups, like a real interviewer.

