
Two Pointers: The Pattern Inside Sorted Array Problems
I've been breaking down coding patterns that took me too long to internalize. The two pointer technique is the one I wish I'd studied first. It shows up in so many problems on LeetCode and in coding interviews that understanding it early would have saved me hours of brute-force attempts.
Why I kept writing nested loops
For months, my approach to array problems was consistent: try every pair with two nested loops. It worked, but it was almost always too slow. The two pointers approach existed everywhere in editorial solutions, but nobody explained the reasoning behind it. Tutorials jumped from "given a sorted array" straight to the answer.
I kept defaulting to brute force and timing out on problems that had O(n) solutions using the two pointer algorithm.
The core idea behind two pointers
The two pointer technique places two index variables at positions in your array and moves them based on conditions. The key insight is that sorting gives you directional guarantees. If your current sum is too small, moving the left pointer right makes it bigger. If too big, moving the right pointer left makes it smaller. You never guess which direction to move.
On an unsorted array, moving a pointer could increase or decrease values unpredictably. Sorting means each pointer movement eliminates an entire set of impossible combinations. That elimination is why two pointers turns O(n²) into O(n).

Two Sum on a sorted array: the foundation
Given a sorted array and target sum, find two numbers that add up to the target.
def two_sum_sorted(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 []Walk through it with nums = [1, 3, 5, 7, 9] and target = 8. Start with left = 0 (value 1), right = 4 (value 9). Sum is 10, too big. Move right to 3. Now sum is 8. Done in 2 checks instead of 10.
When we moved right from index 4 to 3, we skipped pairs like (3,9) and (5,9). This is safe because the array is sorted. If nums[0] + nums[4] = 10 is too big, then every other pair with nums[4] is also too big since nums[1] >= nums[0]. One move eliminates an entire column of pairs.
Three variations of two pointers
Variation 1: Opposite ends moving inward
This is the Two Sum pattern. Start at both ends, move inward based on comparisons. Container With Most Water uses this approach. You maximize the area between two heights by always moving the pointer at the shorter height.
def max_area(height):
left, right = 0, len(height) - 1
best = 0
while left < right:
width = right - left
h = min(height[left], height[right])
best = max(best, width * h)
if height[left] < height[right]:
left += 1
else:
right -= 1
return bestVariation 2: Fast and slow pointers
Both pointers start at the beginning. One moves faster. This is Floyd's cycle detection algorithm applied to arrays. Remove Duplicates from a Sorted Array demonstrates it clearly.
def remove_duplicates(nums):
if not nums:
return 0
slow = 0
for fast in range(1, len(nums)):
if nums[fast] != nums[slow]:
slow += 1
nums[slow] = nums[fast]
return slow + 1The slow pointer advances only when a new unique value appears. The fast pointer scans ahead continuously. Their divergence tracks exactly how many duplicates exist.
Variation 3: Expanding from center
Start both pointers at one position and expand outward. This is the standard approach for palindrome two pointers problems.
def longest_palindrome(s):
def expand(left, right):
while left >= 0 and right < len(s) and s[left] == s[right]:
left -= 1
right += 1
return s[left + 1:right]
result = ""
for i in range(len(s)):
odd = expand(i, i)
even = expand(i, i + 1)
result = max(result, odd, even, key=len)
return resultEach center expansion takes O(n) worst case across n centers, giving O(n²) total. Still much better than O(n³) brute force checking every substring.
Two pointers vs sliding window

These two patterns both use two indices and avoid nested loops, but the intent differs. Two pointers works on sorted data with pointer movement driven by value comparisons. Sliding window maintains a contiguous subarray satisfying some property on sequential data.
Sliding window is technically a special case of two pointers where both move in the same direction and the gap represents a contiguous subarray. But the problem-solving approach differs. Sorted array with pairs means two pointers. Contiguous subarrays maintaining a property means sliding window.
I wrote about the sliding window pattern in detail here. The two patterns complement each other by covering different shapes of the same optimization.
Common mistakes with two pointers
Forgetting to sort first is the most common error. The two pointer technique depends on sorted order for directional guarantees. On unsorted data, pointer movements become unpredictable.
Not handling duplicates causes bugs in problems like 3Sum. After finding a valid triplet, advance both pointers past duplicate values.
def three_sum(nums):
nums.sort()
result = []
for i in range(len(nums) - 2):
if i > 0 and nums[i] == nums[i-1]:
continue
left, right = i + 1, len(nums) - 1
while left < right:
total = nums[i] + nums[left] + nums[right]
if total == 0:
result.append([nums[i], nums[left], nums[right]])
while left < right and nums[left] == nums[left + 1]:
left += 1
while left < right and nums[right] == nums[right - 1]:
right -= 1
left += 1
right -= 1
elif total < 0:
left += 1
else:
right -= 1
return resultUsing two pointers when a hash map is simpler wastes effort. For unsorted Two Sum where you need indices, a hash map gives O(n) without sorting. The two pointer approach works best when data is already sorted or sorting preserves the needed information.
How to identify two pointer problems
Look for these signals in problem statements: the array is sorted or can be sorted without losing information. You need pairs, triplets, or subsequences satisfying a condition. Brute force requires nested loops. Moving one pointer consistently increases or decreases a relevant value.
Practice problems for two pointers
Two Sum II (sorted input) is the foundational two pointers LeetCode problem. Explain why each pointer movement is safe to confirm understanding.
3Sum extends the two pointer technique with an outer loop. Duplicate handling is the challenge, not the pointer logic.
Container With Most Water tests the elimination argument outside a typical "find a pair" context.
Remove Duplicates from Sorted Array is the cleanest fast/slow pointer problem.
Longest Palindromic Substring practices center expansion.
Trapping Rain Water combines the two pointer algorithm with extra bookkeeping. The core logic is the same opposite-ends pattern.
After those, try the problems on Levelop's coding patterns track. That's where I worked through these variations and started seeing the connections.
Frequently Asked Questions
What is the two pointer technique in coding interviews?
The two pointer technique uses two index variables traversing a data structure simultaneously. Moving pointers based on conditions eliminates nested loops, reducing time complexity from O(n²) to O(n). It is one of the most tested patterns at Google, Amazon, and Meta.
When should I use two pointers instead of a hash map?
Use two pointers when input is sorted or sorting preserves needed information. Use a hash map when original positions matter or data cannot be meaningfully sorted. For unsorted Two Sum needing indices, a hash map works better. For sorted Two Sum or 3Sum, the two pointer approach is cleaner.
What is the difference between two pointers and sliding window?
Two pointers works on sorted data using value comparisons for pairs and triplets. Sliding window maintains contiguous subarrays satisfying properties on sequential data. Sliding window is a specialized form of two pointers where both move in the same direction, but the problem-solving mindset is different.
How do I handle duplicates in two pointer problems?
After finding a valid result, skip duplicate values by advancing the pointer while the next value equals the current one. In 3Sum, after finding a triplet, advance the left pointer past all copies and the right pointer past all copies before continuing.
Can two pointers work on unsorted arrays?
Generally no. The two pointer technique relies on sorted order for directional guarantees. On unsorted data, pointer movement gives no predictable information about whether results move toward or away from the target. Sort the array first at O(n log n) cost, or use a different technique like hash maps.
