Rahul Kumar

Yesterday we learned that two pointers do not always face opposite directions. Both pointers moved from the left at different speeds to solve the Move Zeroes problem.
Today, we flip the script.
LeetCode 167 Two Sum II is where we see the classic form of the two pointer pattern: one pointer starting from the left, one from the right, both moving toward each other until they find the answer.
But what makes this problem genuinely interesting is not the pointers themselves. It is the reason we can use them at all. And that reason is one word: sorted.
Given a 1-indexed array of integersnumbersthat is already sorted in non-decreasing order, find two numbers such that they add up to a specific target number. Return the indices of the two numbers as[index1, index2].
Constraints to keep in mind:
1 <= index1 < index2 <= numbers.length (you cannot use the same element twice)Examples:
Input: numbers = [2, 7, 11, 15], target = 9 Output: [1, 2] Input: numbers = [2, 3, 4], target = 6 Output: [1, 3] Input: numbers = [-1, 0], target = -1 Output: [1, 2]
Before we talk about pointers, let us talk about what "sorted" actually gives us.
Imagine you are looking at the array [2, 7, 11, 15]. You pick two numbers and check their sum.
This single observation is what makes the two pointer approach possible. Every time we check a sum, we get a clear, binary instruction: go left or go right. There is no guessing.
Compare this with the original Two Sum problem (LeetCode 1) where the array is unsorted. There, we have no such guidance, so we need a hash map to remember what we have seen. That costs O(n) space.
Here, the sorted order replaces the hash map entirely. We get O(1) space as a result.
A natural first instinct for this problem might be to try every pair of numbers and check if they sum to the target. That works, but it is O(n²). For an array of 30,000 elements, that is 900 million operations. Not acceptable.
A slightly smarter instinct might be to use a hash map, the same approach as Two Sum I. That gives O(n) time but O(n) space, which violates the constant space constraint of this problem.
The right instinct comes from reading the problem carefully and asking: what does sorted give me that unsorted does not?
It gives you direction. And direction is all you need.
We place two pointers at opposite ends of the array:
fp (first pointer) starts at index 0, the smallest elementsp (second pointer) starts at the last index, the largest elementAt each step, we calculate the sum of the elements at both pointers and make a decision:
sum > target, the sum is too large. We need a smaller number on the right side, so we move sp one step to the left.sum < target, the sum is too small. We need a larger number on the left side, so we move fp one step to the right.sum === target, we found our answer.Because exactly one solution is guaranteed, the pointers will always meet the answer before crossing each other.
Let us trace through each example carefully.
numbers = [2, 7, 11, 15]
target = 9
Initial State:
fp = 0 (points to 2)
sp = 3 (points to 15)Iteration 1
Array: [2, 7, 11, 15]
^ ^
fp=0 sp=3
numbers[fp] = 2
numbers[sp] = 15
sum = 2 + 15 = 17sum (17) > target (9), so we need a smaller number on the right side.
Action: Move sp one step to the left.
After Iteration 1:
fp = 0 (still points to 2)
sp = 2 (now points to 11)Iteration 2
Array: [2, 7, 11, 15]
^ ^
fp=0 sp=2
numbers[fp] = 2
numbers[sp] = 11
sum = 2 + 11 = 13sum (13) > target (9), still too large. We need to go smaller on the right again.
Action: Move sp one step to the left.
After Iteration 2:
fp = 0 (still points to 2)
sp = 1 (now points to 7)Iteration 3
Array: [2, 7, 11, 15]
^ ^
fp=0 sp=1
numbers[fp] = 2
numbers[sp] = 7
sum = 2 + 7 = 9sum (9) === target (9). Solution found!
The problem uses 1-based indexing, so we return [fp + 1, sp + 1].
Output: [0 + 1, 1 + 1] = [1, 2]numbers = [2, 3, 4]
target = 6
Initial State:
fp = 0 (points to 2)
sp = 2 (points to 4)Iteration 1
Array: [2, 3, 4]
^ ^
fp=0 sp=2
sum = 2 + 4 = 6sum (6) === target (6). Found on the very first check!
Output: [0 + 1, 2 + 1] = [1, 3]numbers = [-1, 0]
target = -1
Initial State:
fp = 0 (points to -1)
sp = 1 (points to 0)Iteration 1
Array: [-1, 0]
^ ^
fp=0 sp=1
sum = -1 + 0 = -1sum (-1) === target (-1). Found immediately!
Output: [0 + 1, 1 + 1] = [1, 2]This example confirms the approach works correctly with negative numbers too.
Let us think about why this approach is not just correct but also complete.
1. Every pointer move eliminates impossible pairs permanently.
When sp moves left because the sum was too large, we are not just trying the next pair. We are saying: the current fp value combined with anything at or to the right of the old sp cannot possibly equal the target. We eliminate an entire column of pairs in one step.
2. The pointers can never skip the solution.
The key guarantee is that the array is sorted. If the solution exists at positions i and j, then at some point fp will reach i and sp will be at j, or vice versa. The pointer movements are always directional and informed, so neither pointer can jump past the answer.
3. Exactly one solution means we never need backtracking.
If there were multiple solutions, we might worry about missing one. But the constraint tells us there is exactly one. So the moment we find a matching sum, we are done, no further checks needed.
4. The loop terminates because fp < sp is enforced.
Since we cannot use the same element twice and fp only moves right while sp only moves left, they will eventually cross. But they will find the answer before that happens, guaranteed by the exactly one solution constraint.
var twoSum = function(numbers, target) {
let fp = 0; // Start from the smallest element
let sp = numbers.length - 1; // Start from the largest element
while (fp < sp) {
let sum = numbers[fp] + numbers[sp];
if (sum > target) sp--; // Sum too large, bring right pointer in
if (sum < target) fp++; // Sum too small, push left pointer out
if (sum === target) break; // Found it
}
return [fp + 1, sp + 1]; // Convert to 1-based indexing
};Line by line breakdown:
let fp = 0 sets the first pointer at the smallest element in the array.let sp = numbers.length - 1 sets the second pointer at the largest element.while (fp < sp) ensures we never use the same element twice. When they meet, we stop.sum > target means the right value is too large, so sp comes in from the right.sum < target means the left value is too small, so fp goes out to the right.sum === target means we found our pair and break the loop.return [fp + 1, sp + 1] converts from 0-based to 1-based indexing as required.Complexity
Explanation
Time
O(n)
Each element is visited at most once. The two pointers together make at most n steps total.
Space
O(1)
Only two integer pointers are used. No extra arrays or hash maps.
This is optimal for this problem. You cannot avoid reading the input, so O(n) time is the lower bound.
Mistake 1: Using a hash map like Two Sum I.
javascript
// Works but violates the constant space constraint const seen = new Map();
This is a valid general approach but the problem explicitly requires O(1) space. A sorted array makes the hash map unnecessary, so using one here misses the point of the problem entirely.
Mistake 2: Forgetting the 1-based index conversion.
javascript
// Wrong return [fp, sp]; // Correct return [fp + 1, sp + 1];
The problem clearly states it is 1-indexed. This is an easy mistake to make under interview pressure. Always re-read the output format before writing the return statement.
Mistake 3: Using else if incorrectly in the condition chain.
javascript
// Risky version if (sum > target) sp--; else if (sum < target) fp++; else break;
This version works, but be careful with the order. A cleaner mental model is to check all three cases independently or restructure with else if and else so exactly one branch runs per iteration.
Mistake 4: Not trusting the sorted property.
Some candidates try to sort the array themselves before applying two pointers, not realising the array is already sorted. Always read the problem constraints fully before writing any code.
If this question comes up in an interview, here is how to structure your thinking out loud:
The opposite ends two pointer approach on sorted arrays appears across many problems:
Once you understand why sorted arrays allow opposite end pointer movement, these problems become recognisable patterns rather than new puzzles.
After Day 1 and Day 2, we have now seen both main forms of the two pointer pattern. It is worth pausing to compare them.
Day 1: Move Zeroes
Day 2: Two Sum II
Direction
Both pointers move left to right
Pointers move toward each other
Speed
Different speeds (fast and slow)
Condition based movement
Array type
Unsorted
Sorted
Why it works
One pointer collects, one scans
Sorted order gives direction
Recognising which variation fits a problem is a skill in itself. The key question to ask is always: does the array being sorted give me directional information? If yes, opposite end pointers. If not, look for a fast slow approach or a different strategy entirely.
Day 2 ✅
We have now seen both major forms of the two pointer pattern. The fast slow version and the opposite ends version. These two ideas will keep appearing in different forms throughout this challenge.
Day 3 is coming tomorrow with another problem, another pattern, and another full breakdown.
If you are following along, drop a comment with your solution or any questions. And if you found this helpful, consider following the Medium list so you do not miss any posts.
See you on Day 3. 🚀
This post is part of my 250 Days DSA Challenge, solving one problem every day with a focus on intuition, patterns, and interview ready thinking.
Day 4 of the 250 Days DSA Challenge. LeetCode 11 Container With Most Water is a visual problem hiding a clean logical constraint. This post breaks down the full approach with a detailed dry run, pointer movement reasoning, and interview ready insights.
Rahul Kumar
LangChain's Model component is the core of every AI app. Learn how LLMs, Chat Models, and Embeddings actually work - from token generation to semantic search - with practical code and real-world examples.
Sign in to join the discussion.
Sameer Singh