The Two-Pointer Technique Explained
The two-pointer technique uses two indices moving through data to solve pair, partition, and in-place problems in O(n) without nested loops. Here are the three variations, with examples and when to use each.
The two-pointer technique uses two indices moving through your data to solve a problem in one pass — replacing a nested loop and turning O(n²) into O(n). Depending on the problem, the pointers start at opposite ends and close in, move at different speeds, or travel together in the same direction.
It’s one of the first patterns to learn because it’s simple, widely applicable, and a direct upgrade over brute force on a huge class of array, string, and linked-list problems.
Variation 1 — Opposite ends (converging)
Put one pointer at the start, one at the end, and move them toward each other. The classic use is finding a pair that sums to a target in a sorted array:
let lo = 0, hi = arr.length - 1;
while (lo < hi) {
const sum = arr[lo] + arr[hi];
if (sum === target) return [lo, hi];
sum < target ? lo++ : hi--; // too small → raise low; too big → lower high
}
Because the array is sorted, each comparison lets you discard one option, so it’s O(n) instead of O(n²). The same shape solves palindrome checks (compare ends inward) and reversing in place (swap ends, move inward).
Variation 2 — Fast and slow (different speeds)
Two pointers moving at different speeds shine on linked lists:
// Find the middle: when fast reaches the end, slow is halfway
let slow = head, fast = head;
while (fast && fast.next) {
slow = slow.next; // 1 step
fast = fast.next.next; // 2 steps
}
// slow is the middle
The same fast/slow idea detects a cycle (if they meet, there’s a loop) and finds the nth node from the end (start one pointer n ahead).
Variation 3 — Same direction (slow writer, fast reader)
Two pointers moving the same way, one reading and one writing, do in-place filtering. The classic is removing duplicates from a sorted array:
// Compact unique values to the front; return new length
let write = 0;
for (let read = 0; read < arr.length; read++) {
if (read === 0 || arr[read] !== arr[read - 1]) {
arr[write++] = arr[read]; // keep it
}
}
return write;
The same pattern partitions an array (move all zeros to the end, Dutch-flag problems). When both same-direction pointers maintain a contiguous range, you’ve got a sliding window — its special case.
When to recognise it
Reach for two pointers when you see:
- A sorted array and a pair or triplet to find (two-sum, three-sum).
- In-place rearrangement (reverse, partition, remove duplicates) with O(1) extra space.
- Palindrome or “compare from both ends”.
- Linked-list middle, cycle, or nth-from-end.
If you’re tempted to write a nested loop over the same array, pause — there’s often a two-pointer solution.
Common mistakes
- Using opposite-ends on an unsorted array — it relies on order. Sort first (O(n log n)) or switch to a hash map.
- Pointer-crossing bugs — be precise about
lo < hivslo <= hi. - Null checks with fast/slow on linked lists — guard
fast && fast.nextbefore stepping twice. - Overwriting data you still need in same-direction in-place writes — the write pointer must never get ahead of the read pointer.
Where this fits
The two-pointer technique is a Phase 3 pattern in the coding interview roadmap, foundational to arrays and strings, linked lists, and the sliding window (its same-direction special case).
The three variations, with worked examples, are drawn out in our job-ready tier — JavaScript in Three Months, Python in Three Months, and Java in Three Months. For multi-pointer problems (three-sum, trapping rain water, merge intervals) that show up in senior rounds, the for Staff Engineers tier goes deeper: JavaScript, Python, Java.
Two indices, one pass — it’s the simplest way to beat a nested loop.
Frequently asked questions
What is the two-pointer technique?
The two-pointer technique uses two index variables that move through a data structure to solve a problem in a single pass. Depending on the problem the pointers start at opposite ends and move toward each other, move at different speeds, or move in the same direction — replacing a nested loop and turning O(n²) into O(n).
When should I use two pointers?
Use two pointers when a problem involves a sorted array and pairs (two-sum, three-sum), checking a palindrome, reversing or partitioning in place, or finding a cycle or the middle of a linked list. The signals are 'sorted', 'pair', 'in place', or 'compare from both ends'.
What is the difference between two pointers and a sliding window?
A sliding window is a specific kind of two-pointer technique where both pointers move in the same direction to maintain a contiguous range. The broader two-pointer technique also includes pointers moving toward each other from opposite ends, and fast/slow pointers moving at different speeds.
Does the two-pointer technique require a sorted array?
The opposite-ends variation (for pair sums and partitioning) usually requires a sorted array, so you may need to sort first at O(n log n). The same-direction and fast/slow variations do not require sorting — they work on linked lists and unsorted arrays.