Lesson 52 of 80
Two indices walking through an array instead of one nested loop inside another — the difference between O(n) and O(n squared) on a whole class of problems.
15 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
This topic is about judgment and practical tradeoffs more than a single right answer — a mock interview is the better way to test yourself on it.
Be interviewed on this →Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
A lot of array problems get solved with a nested loop by default: for each element, loop through the rest of the array looking for a match. That's O(n²), and most of the time it's more work than the problem actually needs.
The two-pointer technique replaces the inner loop with a second index that moves with intent — from the opposite end of the array, or one step ahead of the first pointer — using information you already have (usually: the array is sorted) to decide which pointer to move next. One pass, two positions, no nested loop.
Pair that sums to a target, in a sorted array. Nested-loop instinct: check every pair, O(n²). Two-pointer version: start one pointer at each end and use the sum to decide who moves.
function twoSum(sortedArr, target) {
let left = 0;
let right = sortedArr.length - 1;
while (left < right) {
const sum = sortedArr[left] + sortedArr[right];
if (sum === target) return [left, right];
if (sum < target) left++; // sum too small — need a bigger number
else right--; // sum too big — need a smaller number
}
return null;
}
twoSum([1, 3, 5, 7, 9, 11], 12); // [1, 4] → 3 + 9
Because the array is sorted, moving left right only increases the sum, and moving right left only decreases it. That monotonic behavior is what lets you throw away half the remaining possibilities on every step, instead of checking them all.
Reversing an array in place. Nested-loop instinct doesn't even apply here, but the naive approach (.reverse() aside) is to build a new array. Two pointers do it without one:
function reverseInPlace(arr) {
let start = 0;
let end = arr.length - 1;
while (start < end) {
[arr[start], arr[end]] = [arr[end], arr[start]];
start++;
end--;
}
return arr;
}
Each swap fixes two elements at once, and the pointers meet in the middle — exactly n / 2 swaps for n elements.
left < right, not left <= right — when they're equal (or have crossed), there's nothing left to compare, and processing that "pair" would double-count a single element.reduce collapses an array into one value in a single pass by carrying an accumulator forward. Two pointers is the same underlying trade — using a single pass with a bit of extra state (here, a second index) to avoid the repeated re-scanning a nested loop would do. Different shape, same instinct: notice what a naive double loop recomputes, and carry just enough state to not recompute it.