What two pointers is
[2, 3, 5, 8, 11] — and a target, 13. Which two values add up to it? The brute-force move is to check every pair (2+3, 2+5, 2+8, …) — a loop inside a loop, O(n²), that completely ignores the sortedness.sum = arr[left] + arr[right]:- sum too small (
sum < target)? The only way up is a bigger small value → move left rightward. - sum too big (
sum > target)? The only way down is a smaller big value → move right leftward. - sum just right? Found it.
Quick check
In sorted pair-sum, the current sum is too BIG. You move…
Answer it in the interactive lesson to keep your progress.
How it works, step by step
13. Instead of testing every pair, we put one marker at each end and move them toward each other, letting the sorted order tell us which one to move.The steps
- Put
lefton the first element andrighton the last. - Look at
sum = arr[left] + arr[right]. - If
sumequals the target → found the pair. - If
sumis too small, the only way to grow it is a bigger low value → moveleftrightward. - If
sumis too big, the only way to shrink it is a smaller high value → moverightleftward. - Stop when the markers meet (
left >= right) — no pair exists.
Trace it on [2, 3, 5, 8, 11], target 13 (L=0→2, R=4→11):
2 + 11 = 13→ match, done.
10: 2 + 11 = 13 too big → R=3; 2 + 8 = 10 → match. Each step throws away pairs you never have to test. In JavaScript, one way to write those steps:left moves" or "too big, right moves." If your call and the animation ever disagree, replay that step: it is the whole algorithm in one move.This section has a step-by-step animation in the interactive lesson.
function twoSumSorted(sorted, target) {
let lo = 0, hi = sorted.length - 1; // one marker at each end
while (lo < hi) {
const sum = sorted[lo] + sorted[hi];
if (sum === target) return [lo, hi];
if (sum < target) lo++; // too small → raise the low end
else hi--; // too big → lower the high end
}
return [-1, -1]; // markers crossed → no pair
}
console.log(twoSumSorted([2, 3, 5, 8, 11], 13)); // [0, 4]
console.log(twoSumSorted([2, 3, 5, 8, 11], 10)); // [0, 3]Quick check
On [2, 3, 5, 8, 11] with target 10: after 2 + 11 = 13 (too big), predict the next comparison.
Answer it in the interactive lesson to keep your progress.
Where it breaks (and how not to get burned)
- Unsorted input. The move-left/move-right logic only works because the array is sorted. If it is not, sort first — or reach for a hash map instead.
- Moving the wrong pointer. Nudge the wrong side and you will skip the answer or loop forever. Tie each move to why: too small → raise the low end; too big → lower the high end.
- Crossing the pointers. Stop when
left >= right; reading past that double-counts or reprocesses the middle.
Quick check
Opposite-ends two pointers on UNSORTED data…
Answer it in the interactive lesson to keep your progress.
How fast is it? (complexity)
| Approach to pair-sum (sorted) | Time | Space | Why |
|---|---|---|---|
| brute force — every pair | O(n²) | O(1) | ignores the sorted order |
| two pointers — sweep inward | O(n) | O(1) | each step retires one end |
n moves they meet — that is the whole O(n) argument, and no extra memory is needed.- Keep two indices and move them by a rule instead of nesting loops.
- Opposite-ends needs sorted data; a slow/fast pair (dedupe, reverse) does not.
- One
O(n)sweep,O(1)space — stop when the pointers cross.
This section has a step-by-step animation in the interactive lesson.
function dedupe(sortedArr) {
if (sortedArr.length === 0) return 0;
let write = 0;
for (let read = 1; read < sortedArr.length; read++) {
if (sortedArr[read] !== sortedArr[write]) {
write++;
sortedArr[write] = sortedArr[read];
}
}
return write + 1;
}
const data = [1, 1, 2, 2, 2, 3];
const uniqueLen = dedupe(data);
console.log('unique count:', uniqueLen);
console.log('front of array:', data.slice(0, uniqueLen));