Two pointers replaces a nested loop with two indexes moving intelligently through the data — O(n²) becomes O(n). It comes in two flavours.
Flavour 1: Converging pointers (sorted data)
Start one pointer at each end; move them toward each other based on a comparison.
// Pair with target sum in a SORTED array
function pairSum(nums, target) {
let lo = 0, hi = nums.length - 1;
while (lo < hi) {
const sum = nums[lo] + nums[hi];
if (sum === target) return [lo, hi];
if (sum < target) lo++; // need bigger → move left pointer right
else hi--; // need smaller → move right pointer left
}
return [-1, -1];
}Why it works: sorting gives you information. If the sum is too small, only moving lo right can increase it — you safely skip every pair you never checked.
Flavour 2: Reader/writer pointers (in-place edits)
One pointer reads every element; the other writes only the elements you keep.
// Move all zeroes to the end, in place
function moveZeroes(nums) {
let write = 0;
for (let read = 0; read < nums.length; read++) {
if (nums[read] !== 0) nums[write++] = nums[read]; // keep it
}
while (write < nums.length) nums[write++] = 0; // fill the rest
return nums;
}Spot it when…
- The array is sorted (or you can sort it) and you need pairs/triplets.
- You must edit in place without extra space (remove duplicates, partition).
- Palindrome checks — compare from both ends inward.
Practice now on the judge
- Move Zeroes — reader/writer
- Remove Duplicates (Sorted) — reader/writer
- Valid Palindrome — converging
Complexity: O(n) time, O(1) space — say both in the interview. Next: Sliding Window, two pointers' famous cousin.