Two Pointers Pattern Explained
Master the two pointers technique for solving array and string problems efficiently. Learn when to use it and common problem patterns.
What is the Two Pointers Pattern?
The two pointers pattern is a technique where you use two pointers (usually indices) to iterate through a data structure, often an array or string. Instead of using nested loops which would give O(n²) time complexity, two pointers can solve many problems in O(n) time.
When to Use Two Pointers
Consider the two pointers pattern when:
- Working with sorted arrays or strings - The sorted order lets you make decisions based on comparisons
- Finding pairs or triplets that meet certain criteria
- Checking for palindromes - Compare characters from both ends
- Removing duplicates in-place from a sorted array
- Reversing an array or string
- Finding subarrays that meet a condition (often combined with sliding window)
Pattern Variations
1. Opposite Ends (Convergent Pointers)
Start with one pointer at the beginning and another at the end, moving them toward each other. Common for sorted arrays and palindromes.
function twoSum(numbers: number[], target: number): number[] {
let left = 0
let right = numbers.length - 1
while (left < right) {
const sum = numbers[left] + numbers[right]
if (sum === target) {
return [left, right]
} else if (sum < target) {
left++ // Need larger sum
} else {
right-- // Need smaller sum
}
}
return [-1, -1]
}
// Example: twoSum([1, 2, 3, 4, 5], 7) → [1, 4]
// Because numbers[1] + numbers[4] = 2 + 5 = 72. Same Direction (Fast & Slow Pointers)
Both pointers start at the beginning but move at different speeds. Often used for in-place modifications or cycle detection.
function removeDuplicates(nums: number[]): number {
if (nums.length === 0) return 0
let slow = 0
for (let fast = 1; fast < nums.length; fast++) {
if (nums[fast] !== nums[slow]) {
slow++
nums[slow] = nums[fast]
}
}
return slow + 1
}
// Example: removeDuplicates([1,1,2,2,3]) → 3
// Array becomes [1,2,3,2,3], return length 33. Distance-Based Pointers
Maintain a specific distance between pointers. Useful for problems like "find the nth element from the end."
function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null {
const dummy = new ListNode(0, head)
let first = dummy
let second = dummy
// Move first pointer n+1 steps ahead
for (let i = 0; i <= n; i++) {
first = first.next!
}
// Move both until first reaches end
while (first !== null) {
first = first.next!
second = second.next!
}
// Remove the nth node
second.next = second.next!.next
return dummy.next
}Common Problems & Solutions
Problem 1: Valid Palindrome
Question: Given a string, determine if it's a palindrome, considering only alphanumeric characters and ignoring cases.
function isPalindrome(s: string): boolean {
let left = 0
let right = s.length - 1
while (left < right) {
// Skip non-alphanumeric from left
while (left < right && !isAlphaNum(s[left])) {
left++
}
// Skip non-alphanumeric from right
while (left < right && !isAlphaNum(s[right])) {
right--
}
// Compare characters (case-insensitive)
if (s[left].toLowerCase() !== s[right].toLowerCase()) {
return false
}
left++
right--
}
return true
}
function isAlphaNum(c: string): boolean {
return /[a-zA-Z0-9]/.test(c)
}Problem 2: Container With Most Water
Question: Given an array of heights, find two lines that together with the x-axis form a container that holds the most water.
function maxArea(height: number[]): number {
let left = 0
let right = height.length - 1
let maxWater = 0
while (left < right) {
// Calculate current area
const width = right - left
const currentHeight = Math.min(height[left], height[right])
const area = width * currentHeight
maxWater = Math.max(maxWater, area)
// Move pointer with smaller height
if (height[left] < height[right]) {
left++
} else {
right--
}
}
return maxWater
}
// Key insight: Moving the smaller height gives us a chance
// to find a taller line that increases the areaTime & Space Complexity
Time Complexity: O(n) - We traverse the array once with both pointers
Space Complexity: O(1) - Only using pointer variables, no extra data structures
Pro Tips
- Draw it out: Visualize the pointers moving through examples
- Edge cases: Empty array, single element, all elements the same
- Sorted requirement: Many two-pointer problems need sorted input
- Decision criteria: Always know why you're moving each pointer
- Loop condition: Usually
left & lt; rightfor opposite ends
Practice Problems
Ready to test your understanding? Try these LeetCode problems:
- Easy: Valid Palindrome, Remove Duplicates from Sorted Array
- Medium: 3Sum, Container With Most Water, Longest Substring Without Repeating Characters
- Hard: Trapping Rain Water, Minimum Window Substring
Practice with HireReady
Our platform includes 100+ two pointers problems with spaced repetition to ensure long-term retention. Start practicing now!
Start Free Practice →Continue Learning
- Sliding Window Technique — Often combined with two pointers for subarray problems
- Big O Notation Explained — Understand why two pointers achieves O(n) time
- Hash Maps: When and Why — Another approach for pair-finding problems
- Start Practicing — Apply two pointers to real interview problems