Two Pointers Pattern
Compare from both ends. Eliminate half the work at every step.
Quick Summary
Best used when
- ✓You need to compare elements at two ends of an array or string
- ✓You need to find a pair in a sorted array that satisfies a condition
- ✓You need to check whether something is a palindrome
- ✓You need to move elements in place without extra space
Clue words in the problem
Complexity gain
O(n²) pair checking → O(n) single pass
Why this pattern matters for LeetCode
Nested loops check every possible pair — O(n²). Two Pointers works when the input is sorted or has a structural property that lets you eliminate one end at each step. When the pair doesn't satisfy the condition, you move the pointer that can improve it. One pass, O(n). The key is that you never need to check both ends again after you've moved a pointer — you've already eliminated everything on that side.
What the Two Pointers pattern is
Two pointers are indices that start at different positions and move toward each other (or in the same direction, for some variants) based on a condition. The classic form places one pointer at the start and one at the end, then moves them inward. At each step you decide which pointer to move based on whether the current pair satisfies the condition. This eliminates the need to check every pair, giving O(n) time instead of O(n²).
Reach for Two Pointers when you catch yourself thinking…
These are the internal questions that signal this pattern.
Beginner mental model
Imagine two people walking toward each other from opposite ends of a bridge. They meet in the middle. Neither walks the full bridge — together they cover it in one combined pass. That's two pointers: you eliminate work from both ends simultaneously, so the total work is O(n) instead of O(n²). If the current pair doesn't satisfy the condition, you move the pointer that can improve it — not both, because moving both could skip the answer.
Ready to practice Two Pointers?
DSA Trainer gives you guided hints, not answers, so you build real intuition.
When to use Two Pointers
- ✓Checking if a string is a palindrome (compare left and right, move inward)
- ✓Finding a pair in a sorted array that sums to a target
- ✓Moving all zeroes to the end while maintaining relative order
- ✓Removing duplicates from a sorted array in place
- ✓Container with most water — move the shorter side inward
When NOT to use Two Pointers
- ✕The array is unsorted and sorting would change the problem (index constraints, etc.)
- ✕You need to track what's between the two pointers — that's a Sliding Window
- ✕You need to store data about pairs, not just find them — use a hash map
- ✕You need more than one pass and the pointers can't be determined greedily
Better alternative: In those cases, a Hash Map (for unsorted pair finding) or Sliding Window (for tracking a range) may be better.
JavaScript code template
Valid Palindrome core — O(n) time, O(1) space
function isPalindrome(s) {
// Clean: keep only alphanumeric, lowercase
const cleaned = s.toLowerCase().replace(/[^a-z0-9]/g, "");
let left = 0;
let right = cleaned.length - 1;
while (left < right) {
if (cleaned[left] !== cleaned[right]) {
return false; // mismatch — not a palindrome
}
left++;
right--;
}
return true;
}Left starts at the beginning, right at the end. At each step, compare the characters. If they match, move both inward. If they don't match, it's not a palindrome. The loop stops when the pointers meet or cross. Because each step either confirms a match or exits early, you never look at any character more than once.
Step-by-step thinking process
Walk through this in your head before writing code.
- 1Place left at the start (index 0) and right at the end (index n-1).
- 2Check the current pair — the elements at left and right.
- 3If the condition is met (characters match, sum is correct, etc.), move both pointers inward.
- 4If the condition is not met, decide which pointer to move based on what would improve the result.
- 5Repeat until the pointers meet or cross.
- 6Return the result based on whether all checks passed.
LeetCode-style problems that use this pattern
Practice on DSA Trainer with guided hints: no spoilers, just nudges.
- Valid Palindrome
Check characters from both ends, moving inward — the textbook two-pointer application.
Free→ - Move Zeroes
Use a slow pointer to track where to place the next non-zero element.
Premium→ - Two Sum II — Input Array Is Sorted
Sorted input — move left if sum is too small, move right if too large.
Premium→ - Container With Most Water
Move the shorter wall inward at each step to maximize potential area.
Premium→ - 3Sum
Fix one element, then use two pointers on the rest of the sorted array.
Premium→ - Squares of a Sorted Array
Two pointers from both ends — the largest square is always at one of the two ends.
Premium→
Common mistakes beginners make
- ✕Applying two pointers to an unsorted array when the problem requires sorted order — always check this first.
- ✕Moving both pointers at the same time when only one should move based on the current condition.
- ✕Off-by-one on the loop condition: left < right vs left <= right depends on whether the middle element needs processing.
- ✕Confusing two pointers with sliding window — two pointers usually start at opposite ends or compare two positions; sliding window tracks a contiguous range and what's inside it.
Two Pointers vs Sliding Window
Choose the right tool for the job.
| Pattern | Use when… |
|---|---|
| Two Pointers | You compare or process values at two specific positions, typically moving inward from opposite ends |
| Sliding Window | You track a contiguous range and the state inside it, expanding and shrinking based on a constraint |
Time and space complexity
Time complexity
O(n)
Space complexity
O(1)
Each pointer moves at most n steps total across the whole loop. Together they never move more than n steps combined, so the loop is O(n). No extra data structures — just two integer variables — so space is O(1). (The palindrome cleaning step uses O(n) for the cleaned string, but the core two-pointer traversal itself is O(1) space.)
Ready to practice Two Pointers?
DSA Trainer gives you guided hints, not answers, so you build real intuition.
Frequently asked questions
- When should I use Two Pointers instead of a Sliding Window?
- Use Two Pointers when you're comparing values at two specific positions — usually moving inward from opposite ends. Use Sliding Window when you're tracking a contiguous range and the aggregate state inside it (sum, character count, etc.). If you need to know what's between the two positions, that's a Sliding Window.
- Does Two Pointers always require a sorted array?
- Not always, but often. The classic use cases (Two Sum II, 3Sum, Container With Most Water) need sorted order to know which pointer to move. Palindrome checking works on unsorted strings by symmetry. Move Zeroes works in-place without sorting. Check whether sorted order is required by the specific problem.
- Why is Two Pointers faster than nested loops?
- Nested loops check every pair — n choices for the first pointer times n choices for the second is O(n²). Two Pointers works because at each step, one pointer moves and eliminates everything it passed. Each element is visited at most once per pointer, so both pointers together visit at most 2n positions — O(n) total.
- How does Two Pointers work on Valid Palindrome specifically?
- You start with left pointing to the first character and right pointing to the last. Compare them. If they match, move both inward. If they don't match, it's not a palindrome — return false. When the pointers meet or cross, you've compared all relevant pairs and everything matched — return true.