Two Pointers
A technique that places two markers on the same array and moves them according to a simple rule - often turning an O(n^2) nested loop into a single O(n) pass.
The input is a sorted array or string, or the problem asks you to find a pair or subarray satisfying a condition. If you catch yourself writing a nested loop to compare every pair, stop. Two pointers likely cuts it to one pass.
The motivation should be clear before the demo starts
Two pointers is worth learning because it replaces pair-by-pair brute force with a controlled one-pass rule. You are not just moving pointers around. You are using structure in the input to throw away work.
You compare one element against every other candidate.
The work grows quadratically because the search space is never discarded.
Every comparison gives you a rule for what can be safely ignored next.
The total movement is linear because the pointers never need to backtrack.
See the move, then see the reason behind it
The demo is split into the two core variants of the pattern. Every step explains both what the algorithm just did and why that move was logically correct.
What
Pointers placed at both ends.
Why
The array is sorted, so moving left grows the sum and moving right shrinks it. That gives us a decision rule for every step.
Code For This Pattern
let left = 0;
let right = nums.length - 1;
while (left < right) {
const sum = nums[left] + nums[right];
if (sum === target) {
return [left + 1, right + 1]; // LeetCode #167 is 1-indexed
}
if (sum < target) {
left += 1; // Need a larger sum
} else {
right -= 1; // Need a smaller sum
}
}Opposite direction and same direction solve different jobs
Both versions use two markers on the same array, but the movement rule is different. The best clue is the type of question the problem is asking.
| Aspect | Opposite Direction | Same Direction |
|---|---|---|
| Starting layout | One at each end | Both start left |
| Decision rule | Move the pointer whose side can be eliminated | Move fast always; slow only on a new unique value |
| Best for | Pair sums, palindromes, container problems | Deduplication, partitioning, in-place compaction |
| Classic problems | Two Sum II, Valid Palindrome, 3Sum | Remove Duplicates, Move Zeroes, Merge Sorted Array |
| Complexity | O(n) time, O(1) space | O(n) time, O(1) space |
The short version
- Reach for two pointers when the input is sorted and you need a pair or to compact an array.
- Opposite direction: each comparison tells you which side to discard. Search space provably shrinks every step.
- Same direction: fast reads every element; slow only advances on a new unique value. No backtracking.
- Both patterns: O(n) time, O(1) space. No extra array, no nested loop.
- If the array is unsorted, sort it first. O(n log n) sort is still far cheaper than O(n^2) brute force.