Where it runs
1. The problem
Checking every pair of items costs O(n2), and the Big-O lesson showed how fast that grows. When the data is sorted, or you only care about items next to each other, two moving markers do in one pass what nested loops need n2 steps for.
You have a price list, already sorted from cheap to expensive, and a gift card worth an exact amount. You want two items whose prices add up to exactly that amount, so you spend the card to the last cent.
The first idea is to try every pair: item 1 with item 2, item 1 with item 3, and so on. For a short list that is fine. For a list of a million prices it is a million times a million pairs: the O(n2) trap from lesson 09.
The list is sorted, though, and the order lets you throw away whole parts of the list without checking them. That gives the answer in one pass.
2. In plain words
Take the first test: the prices [1, 3, 4, 6, 8] and the target 10. Put one marker on the cheapest price, 1, and the other on the most expensive, 8. Together they make 9, which is too little.
Which side do you move? The 1 fell short even together with the 8, the largest price there is. With any cheaper price it would fall short by more. So the 1 is in no answer, and you can drop it: move the left marker to 3. Now 3 + 8 = 11, too much. By the same reasoning the other way round, the 8 is too big even with the smallest price left, so drop it: the right marker moves to 6. Then 3 + 6 = 9, too little again, so the left marker moves to 4. And 4 + 6 = 10. Found it.
Each move dropped one price together with every pair it could form, and nothing was checked twice. Four sums were enough instead of all ten pairs.
3. The idea
Put marker lo on the cheapest item and marker hi on the most expensive one. Add up the two prices they point at.
- The sum equals the target: the pair is found. Done.
- The sum is too small: the only way to make it bigger is to take a pricier item instead of the cheap one. Move
loone position to the right. - The sum is too big: move
hione position to the left so the sum gets smaller.
Each step is safe because the list is sorted. Say the sum is too small. Then nums[lo] falls short of the target even together with the largest remaining price, nums[hi]. With every other, cheaper price it falls short by more. So nums[lo] is in no valid pair, and you can drop it. Stop when the markers meet.
Trace it on [1, 3, 4, 6, 8] with target 10. lo points at 1 and hi at 8: the sum is 9, too small, move lo. lo at 3, hi at 8: the sum is 11, too big, move hi. lo at 3, hi at 6: the sum is 9, too small, move lo. lo at 4, hi at 6: the sum is 10, found. The answer is positions 2 and 3.
4. What it costs
Time is O(n): each marker only moves inward, so together they take at most n steps. Memory is O(1): two variables with indices, and nothing grows with the input. If the list has to be sorted first, add O(n log n) for the sort.
Compare it with the hash approach from lesson 18. It also finds a pair in O(n) time, but it spends O(n) memory on a set. On data that is already sorted, two pointers give the same speed and need no extra memory.
5. Where this shows up
Payment matching: in a ledger sorted by amount, find the two original charges that together make up the amount of a refund. An order book (a list of orders sorted by price) matches a buy order with a sell order. Antifraud systems (fraud detection) and deduplication pipelines look through sorted records for a pair that differs by no more than an allowed amount. Wherever money or ordered records are matched, the task looks the same: sorted input and a search for a pair. Two pointers solve it.
twoPointers([1, 2, 4, 6, 8, 11, 15], 14)lo
hi
Find two numbers that add up to 14. The array is sorted, so lo starts at the smallest number and hi at the biggest.
Bars: the sorted numbers. Exactly one pair of them adds up to the target.
One operation is one pair checked. Every frame, each lane does the same number of operations, so the slow one falls behind.
O(n²)O(n)
Operations for n numbers, and roughly how long they take at 100 million simple operations a second. An estimate from the same count, not a measurement.
Recognise it
Say these words and it is this pattern
- sorted array (or you are allowed to sort)
- find a pair/triple with a target sum
- squeeze from both ends (container, area)
- palindrome check
Looks similar, isn't
- Sliding window (variable)
A window keeps a live span and both ends move forward. These pointers start apart and close in.
- Hash set / map
Hashing finds a complement in unsorted data, at the cost of O(n) memory. Two pointers need order but no memory.
- Two pointers (same direction)
There both indices move forward, one reading and one writing. Here they approach from opposite ends.
- Binary search (array)
Binary search hunts one fixed target and halves the range. Here the pair being compared changes every step.
n up to 1e6 on sorted input gives O(n) time. Each pointer moves at most n steps, and space is O(1).
On LeetCode
Problems on a sorted array, or a string read from both ends, where you need a pair with a given sum, a palindrome check or the best pair. Two pointers moving toward each other replace checking every pair.
This is the lesson task, except that the answer counts positions from 1.
Compare the two ends, skip anything that is not a letter or digit, and step inward.
The largest square sits at one of the two ends, so fill the answer from the back.
Move the shorter wall inward, since it caps the area of every pair it is in.
Sort the numbers by value, fix one, then find the missing sum with two pointers on the rest.
Your task (Tier 1)
Write the function twoSumSorted(nums, target).
Find two numbers that add up to target. The list is sorted from low to high, so you can move in from both ends.
- Input:
nums, a list of numbers sorted from low to high, andtarget, a number. Example:[2, 7, 11, 15],9. - Return: the two positions
[lo, hi]of a pair that adds up totarget. If no pair works, returnnull(Nonein Python).
Steps:
- Put a marker
loat the start (position 0) and a markerhiat the last position. - While
lo < hi, computenums[lo] + nums[hi]. If it equalstarget, return[lo, hi]. If the sum is smaller, moveloone step right. If it is bigger, movehione step left. - If the markers meet and no pair was found, return
null.
Done when all tests pass:
[1, 3, 4, 6, 8], target10->[2, 3][2, 7, 11, 15], target9->[0, 1][1, 2, 3, 4, 4], target8->[3, 4](repeated values)[5], target5->null(one item, no pair)[], target0->null(empty list, must not crash)[1, 2, 3], target100->null(no pair reaches it)
Practice
twoSumSorted
twoSumSorted(nums, target) -> [i, j] (0-based indices, i < j) or null
export function twoSumSorted(nums, target) {
// Your code here. The task is described in the box above the editor.
}
Running as a guest
The tests run right here, no account needed. Your code is kept in this browser only. A free account keeps it on every device, marks the step done and shows where you are in the course.
Hint ladder
Stuck? Reveal one rung at a time, but try it yourself first.