You're in an interview. The problem says: "Find two numbers that sum to target."
You've practiced this. You know the pattern. You write:
def twoSum(nums, target):
left, right = 0, len(nums) - 1
while left < right:
current_sum = nums[left] + nums[right]
if current_sum == target:
return [left, right]
elif current_sum < target:
left += 1
else:
right -= 1
return []You submit. Wrong Answer.
The input was [3, 2, 4], target 6. The answer is indices [1, 2] (values 2 and 4). Your code returned [].
What went wrong? You applied the two pointers pattern to an unsorted array, where it fundamentally cannot work. This is one of the most common mistakes beginners make, and it costs interviews.
In this guide, you'll learn why two pointers fails on unsorted arrays, when to use hash maps instead, and how to decide between the two in under 30 seconds.
TL;DR
- Two pointers (opposite direction) requires sorted data to make greedy decisions about pointer movement.
- On unsorted arrays, you can't determine whether to move left or right based on the current sum.
- Use a hash map for unsorted arrays when you need to find pairs and preserve original indices.
- Decision rule: Sorted or can sort → Two Pointers. Unsorted + need indices → Hash Map.
Why Two Pointers Requires Sorted Data
The opposite-direction two pointers pattern relies on a critical property: monotonicity.
The Sorted Array Guarantee
When the array is sorted:
- If
nums[left] + nums[right] < target, you know thatnums[left]is too small. Movingrightleft won't help because all those values are even larger. The only option is to moveleftright to get a larger value. - If
nums[left] + nums[right] > target, you know thatnums[right]is too large. Movingleftright won't help. The only option is to moverightleft.
This monotonic property allows you to make greedy, local decisions that are guaranteed to explore all valid pairs without missing any.
What Breaks on Unsorted Arrays
Consider the unsorted array [3, 2, 4] with target 6.
Initial state:
left = 0(value 3)right = 2(value 4)- Sum = 7 (too large)
Decision point: Sum is too large, so you move right left.
New state:
left = 0(value 3)right = 1(value 2)- Sum = 5 (too small)
Decision point: Sum is too small, so you move left right.
New state:
left = 1(value 2)right = 1(same position, loop terminates)- Missed the answer: indices
[1, 2](values 2 and 4)
Why did we miss it? Because when we moved right from index 2 to index 1, we assumed that index 2 couldn't be part of the answer with any other left value. But that's only true if the array is sorted! In an unsorted array, moving left right might have given us a smaller value (like 2), which would pair with 4.
The Mathematical Proof
In a sorted array, if nums[left] + nums[right] < target:
- For any
j < right,nums[left] + nums[j] ≤ nums[left] + nums[right] < target(becausenums[j] ≤ nums[right]) - Therefore,
nums[left]cannot be part of the answer with any index to its right - We can safely increment
left
This proof breaks down if the array is not sorted because we can't guarantee nums[j] ≤ nums[right].
Example: Two Sum on Unsorted vs Sorted
Unsorted Array (Two Pointers FAILS)
# Input: nums = [3, 2, 4], target = 6
# Expected: [1, 2] (values 2 and 4)
def twoSum(nums, target):
left, right = 0, len(nums) - 1
while left < right:
current_sum = nums[left] + nums[right]
if current_sum == target:
return [left, right]
elif current_sum < target:
left += 1
else:
right -= 1
return []
# Result: [] (WRONG)
# The algorithm skips the valid pair [1, 2]Sorted Array (Two Pointers WORKS)
# Input: nums = [2, 7, 11, 15], target = 9
# This is LeetCode #167: Two Sum II (Input Array Is Sorted)
def twoSum(nums, target):
left, right = 0, len(nums) - 1
while left < right:
current_sum = nums[left] + nums[right]
if current_sum == target:
return [left + 1, right + 1] # 1-indexed
elif current_sum < target:
left += 1
else:
right -= 1
return []
# Result: [1, 2] (CORRECT)
# Values: nums[0]=2, nums[1]=7, sum=9When to Use Hash Map Instead
For unsorted arrays where you need to find pairs, use a hash map (dictionary/object) to store values you've seen.
Hash Map Template for Two Sum
def twoSum(nums, target):
seen = {} # value -> index
for i, num in enumerate(nums):
complement = target - num
if complement in seen:
return [seen[complement], i]
seen[num] = i
return []Time Complexity: O(n)
Space Complexity: O(n)
Why Hash Map Works on Unsorted Data
The hash map doesn't rely on any ordering. For each element, you check if its complement exists in the map. This is a global lookup, not a greedy decision based on sorted order.
The 30-Second Decision Framework
When you see a "find pairs" problem, ask these questions:
Question 1: Is the array sorted?
- Yes → Two Pointers (O(n) time, O(1) space)
- No → Go to Question 2
Question 2: Can I sort the array?
- Yes, and I don't need original indices → Sort first, then Two Pointers
- No, I need original indices → Hash Map
Question 3: What are the space constraints?
- Must be O(1) space → Sort first (if allowed), then Two Pointers
- O(n) space is fine → Hash Map (simpler, no sorting needed)
Visual Decision Tree
Find two numbers that sum to target
|
v
Is array sorted?
/ \
YES NO
| |
v v
Two Pointers Can I sort?
O(n), O(1) / \
YES NO
| |
v v
Need indices? Hash Map
/ \ O(n), O(n)
YES NO
| |
v v
Hash Map Sort + Two Pointers
O(n), O(n) O(n log n), O(1)Common Interview Scenarios
Scenario 1: Two Sum (LeetCode #1)
- Input: Unsorted array
- Requirement: Return original indices
- Solution: Hash Map
- Why not Two Pointers: Sorting would lose original indices
Scenario 2: Two Sum II (LeetCode #167)
- Input: Sorted array
- Requirement: Return 1-indexed positions
- Solution: Two Pointers
- Why not Hash Map: Sorted array allows O(1) space solution
Scenario 3: 3Sum (LeetCode #15)
- Input: Unsorted array
- Requirement: Find all unique triplets (values, not indices)
- Solution: Sort first, then Two Pointers
- Why not Hash Map: Need to avoid duplicates, sorting helps
Code Comparison: All Three Approaches
// Approach 1: Two Pointers (ONLY for sorted arrays)
function twoSumSorted(nums, target) {
let left = 0, right = nums.length - 1;
while (left < right) {
const sum = nums[left] + nums[right];
if (sum === target) return [left, right];
if (sum < target) left++;
else right--;
}
return [];
}
// Approach 2: Hash Map (for unsorted, preserves indices)
function twoSumHashMap(nums, target) {
const map = new Map();
for (let i = 0; i < nums.length; i++) {
const complement = target - nums[i];
if (map.has(complement)) {
return [map.get(complement), i];
}
map.set(nums[i], i);
}
return [];
}
// Approach 3: Sort first, then Two Pointers (when indices don't matter)
function twoSumSortFirst(nums, target) {
// Create array of [value, originalIndex] pairs
const indexed = nums.map((val, idx) => [val, idx]);
indexed.sort((a, b) => a[0] - b[0]);
let left = 0, right = indexed.length - 1;
while (left < right) {
const sum = indexed[left][0] + indexed[right][0];
if (sum === target) {
return [indexed[left][1], indexed[right][1]];
}
if (sum < target) left++;
else right--;
}
return [];
}Common Mistakes to Avoid
Mistake 1: Blindly Applying Two Pointers
Problem: Seeing "find two numbers" and immediately using two pointers without checking if the array is sorted.
Fix: Always check: "Is this array sorted?" before writing left = 0, right = n-1.
Mistake 2: Sorting When You Need Indices
Problem: Sorting the array to use two pointers, then realizing you need to return original indices.
Fix: If the problem asks for indices, use a hash map or track original indices during sorting.
Mistake 3: Using Hash Map on Sorted Arrays
Problem: Using O(n) space when the sorted property allows O(1) space.
Fix: If the array is already sorted, prefer two pointers for better space complexity.
When Two Pointers IS the Right Choice
Two pointers (opposite direction) works perfectly when:
- Array is sorted (or you can sort it)
- You don't need original indices (or can track them)
- You want O(1) space complexity
- The problem involves pairs/triplets in a sorted context
Classic problems:
- Two Sum II (sorted array)
- 3Sum (sort first)
- Container With Most Water
- Trapping Rain Water
- Valid Palindrome
Practice Strategy
To internalize this distinction:
- Solve Two Sum (#1) with a hash map
- Solve Two Sum II (#167) with two pointers
- Compare the two solutions side-by-side
- Solve 3Sum (#15) to see when sorting enables two pointers
- Practice pattern recognition with LeetCopilot's Smart Context to identify sorted vs unsorted scenarios
FAQ
Q: Can two pointers ever work on unsorted arrays?
A: Yes, but not the opposite-direction variant. Same-direction two pointers (fast/slow, or read/write pointers) work on unsorted arrays for problems like "Remove Duplicates" or "Move Zeroes." But for pair-finding problems, you need sorted data.
Q: What if I sort the array first?
A: That works if you don't need the original indices. For example, 3Sum doesn't care about indices, so you can sort. But Two Sum (#1) requires original indices, so sorting breaks the solution.
Q: Is hash map always better than two pointers?
A: No. Hash map uses O(n) space, while two pointers uses O(1) space. On sorted arrays, two pointers is more space-efficient. Also, two pointers is easier to extend to 3Sum, 4Sum, etc.
Q: How do I remember which to use?
A: Use this mnemonic: "Sorted → Pointers, Unsorted → Hash". If you see a sorted array or can sort it without losing required information, use two pointers. Otherwise, use a hash map.
Conclusion
The two pointers pattern is powerful, but it's not universal. It requires sorted data to make greedy decisions about pointer movement. On unsorted arrays, those decisions become arbitrary, and you'll miss valid pairs.
Key takeaways:
- Two pointers (opposite direction) requires sorted arrays
- Use hash maps for unsorted arrays when finding pairs
- Sort first if you don't need original indices
- Always ask: "Is this array sorted?" before choosing your approach
Master this distinction, and you'll never submit a wrong answer due to this mistake again. For more on two pointers variants, see the complete two pointers guide and learn about two pointers vs sliding window.
Next time you see an unsorted array, reach for the hash map. Your interview score will thank you.
Want to Practice LeetCode Smarter?
LeetCopilot is a free browser extension that enhances your LeetCode practice with AI-powered hints, personalized study notes, and realistic mock interviews — all designed to accelerate your coding interview preparation.
Also compatible with Edge, Brave, and Opera
