Two Pointers Pattern in DSA — Complete Guide for Beginners

 This is a pattern guide. After reading this, you will be able to recognise and solve Two Pointers problems confidently — not just memorise one solution.

Let me ask you something.

Have you ever solved a LeetCode problem by running two loops — one inside the other — and it worked fine on small inputs but got a ‘Time Limit Exceeded’ on larger ones?

That’s almost always a sign that the problem has a Two Pointers solution waiting to be discovered.

Two Pointers is one of the most important patterns in DSA. Once you understand it deeply, you’ll start seeing it everywhere — in array problems, string problems, linked list problems, and even some graph problems.

This guide explains everything from scratch. No prior pattern knowledge needed.

What is the Two Pointers Pattern?

The idea is beautifully simple.

Instead of using one index to loop through an array, you use two — and move them strategically based on some condition. This allows you to check pairs, ranges, or partitions in a single pass instead of nested loops.

Here’s the key insight:

💡  A brute force solution that uses two nested loops is O(n²). Two Pointers converts many of those problems to O(n) — a massive improvement.

Think of it like this: imagine you have a sorted array of numbers and you want to find two numbers that add up to a target. The brute force approach checks every pair — that’s n × n combinations. The Two Pointers approach starts one pointer at the left end and one at the right end and works inward — that’s just n steps.

Same result. Dramatically less work.

When Should You Use Two Pointers?

The pattern fits when you spot these signals in a problem:

  • The input is a sorted array or string (or can be sorted without losing the answer)
  • You need to find a pair, triplet, or subarray satisfying some condition
  • You need to compare elements from both ends
  • You need to remove duplicates or partition elements in-place
  • The problem asks to minimise or maximise a window between two positions
⚠️  Not every array problem is a Two Pointers problem. If the array is unsorted and sorting changes the answer, think of a different approach.

The 3 Variations of Two Pointers

Two Pointers is not one technique — it’s a family of three related approaches. Understanding all three is what separates someone who has ‘seen’ the pattern from someone who actually knows it.

Variation 1 — Opposite Ends (Left and Right Pointers)

This is the most classic variation. One pointer starts at the beginning of the array, one starts at the end, and they move toward each other.

You keep moving them based on a condition until they meet.

Visual Dry Run — Is Array a Palindrome?

Let’s check if the string “racecar” is a palindrome.

StepState & Decision
Startleft = 0 (‘r’),  right = 6 (‘r’)  →  match, move both inward
Step 2left = 1 (‘a’),  right = 5 (‘a’)  →  match, move both inward
Step 3left = 2 (‘c’),  right = 4 (‘c’)  →  match, move both inward
Step 4left = 3 (‘e’),  right = 3 (‘e’)  →  left >= right, stop
ResultAll characters matched → it IS a palindrome ✓

Now let’s see this in code Template for this variation.

Code Template

// Use when: sorted array, find pair, compare from both ends
int left = 0, right = arr.size() - 1;
 
while (left < right) {
    if (/* condition met */) {
        // found answer
    } else if (/* need bigger value */) {
        left++;   // move left pointer right
    } else {
        right--;  // move right pointer left
    }
}
💡  Time Complexity: O(n) — we visit each character at most once. Space Complexity: O(1) — no extra space used.

Variation 2 — Same Direction (Slow and Fast Pointers)

In this variation, both pointers start from the same side — usually the beginning — but they move at different speeds or based on different conditions.

This is extremely useful for problems that ask you to modify an array in-place — like removing duplicates or moving specific elements to the end.

Visual Dry Run — Remove Duplicates from Sorted Array

Given: [1, 1, 2, 3, 3, 4]  →  Keep only unique elements in-place.

We use a slow pointer to track where the next unique element should go, and a fast pointer to scan forward.

Stepslow / fast / Action
Startslow = 0, fast = 1   →  arr[0]=1, arr[1]=1  →  same, move fast
Step 2slow = 0, fast = 2   →  arr[0]=1, arr[2]=2  →  different! slow++, arr[slow]=arr[fast]
Step 3slow = 1, fast = 3   →  arr[1]=2, arr[3]=3  →  different! slow++, arr[slow]=arr[fast]
Step 4slow = 2, fast = 4   →  arr[2]=3, arr[4]=3  →  same, move fast
Step 5slow = 2, fast = 5   →  arr[2]=3, arr[5]=4  →  different! slow++, arr[slow]=arr[fast]
ResultArray becomes [1, 2, 3, 4, …], slow+1 = 4 unique elements

Code Template

// Use when: remove duplicates, filter in-place, modify array
int slow = 0;
 
for (int fast = 0; fast < arr.size(); fast++) {
    if (/* arr[fast] meets condition */) {
        arr[slow] = arr[fast];
        slow++;
    }
    // fast always moves; slow only moves when condition is met
}
💡  Time Complexity: O(n). Space Complexity: O(1). The array is modified in-place — no extra array needed.

Variation 3 — Partition Pointers (Dutch National Flag style)

In this variation, you use two pointers to partition an array into sections — usually moving elements of a certain type to one side.

The most famous example is sorting 0s, 1s, and 2s (the Dutch National Flag problem). But the same idea applies to ‘move all zeroes to the end’, ‘separate odd and even numbers’, and more.

Visual Dry Run — Move All Zeroes to the End

Given: [0, 1, 0, 3, 12]  →  Move all 0s to the end without changing order of others.

We use a slow pointer that tracks where the next non-zero should go.

Stepslow / fast / Action
Startslow = 0, fast = 0  →  arr[0]=0  →  it’s 0, just move fast
Step 2slow = 0, fast = 1  →  arr[1]=1  →  non-zero! swap arr[slow] and arr[fast], slow++
Step 3slow = 1, fast = 2  →  arr[2]=0  →  it’s 0, just move fast
Step 4slow = 1, fast = 3  →  arr[3]=3  →  non-zero! swap arr[slow] and arr[fast], slow++
Step 5slow = 2, fast = 4  →  arr[4]=12 →  non-zero! swap arr[slow] and arr[fast], slow++
Result[1, 3, 12, 0, 0]  →  all zeroes at end ✓

Code Template

// Use when: move elements to one side, separate groups
int slow = 0;
 
for (int fast = 0; fast < arr.size(); fast++) {
    if (arr[fast] != TARGET) {
        swap(arr[slow], arr[fast]);
        slow++;
    }
}
💡  Time Complexity: O(n). Space Complexity: O(1). This is a classic in-place partition — no extra array needed.

Time and Space Complexity Summary

VariationTime / Space
Opposite Ends (e.g. palindrome, two sum)O(n) time — O(1) space
Slow & Fast (e.g. remove duplicates)O(n) time — O(1) space
Partition (e.g. move zeroes)O(n) time — O(1) space
Brute Force (nested loops) for comparisonO(n²) time — O(1) space
🚀  All Three Two Pointers variations are O(n) time and O(1) space. That’s why interviewers love asking for it — it shows you can think beyond brute force.

Common Mistakes Beginners Make

Mistake 1 — Using Two Pointers on an Unsorted Array When Sorting Changes the Answer

Two Pointers usually requires sorted input. If you sort the array just to apply two pointers, make sure the problem allows it. For example, if the problem asks for original indices of a pair, sorting will mess them up.

Mistake 2 — Moving Both Pointers When Only One Should Move

In the Opposite Ends variation, you should only move one pointer per step based on the condition — not both. Moving both blindly will cause you to skip valid pairs.

Mistake 3 — Off-by-One Errors in Loop Conditions

Always use left < right as the loop condition for the Opposite Ends variation, not left <= right. When they meet at the same index, there’s nothing left to compare.

Mistake 4 — Forgetting That slow Pointer Doesn’t Always Start at 0

Depending on the problem, the slow pointer might start at index 1 (for remove duplicates, since index 0 is always unique). Read the problem carefully before writing the loop.

⚠️  These mistakes are easy to make under pressure in interviews. Dry run your solution on at least two examples before submitting.

How to Identify a Two Pointers Problem in an Interview

When you read a problem, look for these clues:

If the problem says…Think about…
‘Find a pair that sums to target’Opposite Ends on sorted array
‘Remove duplicates in-place’Slow & Fast pointers
‘Move all zeroes / negatives to one side’Partition pointers
‘Is this string a palindrome’Opposite Ends
‘Minimum window / maximum area between bars’Opposite Ends or Sliding Window
‘Reverse the array / string in-place’Opposite Ends with swap

Practice Problems — Easy to Hard

Now that you understand the pattern, here’s your practice roadmap. Each of these will be covered as a separate post on Daily Dev Notes.

Easy

  • LeetCode #125 — Valid Palindrome (Opposite Ends)
  • LeetCode #283 — Move Zeroes (Partition)
  • LeetCode #26  — Remove Duplicates from Sorted Array (Slow & Fast)
  • LeetCode #344 — Reverse String (Opposite Ends)

Medium

  • LeetCode #167 — Two Sum II — Input Array Is Sorted (Opposite Ends)
  • LeetCode #15  — 3Sum (Two Pointers inside a loop)
  • LeetCode #11  — Container With Most Water (Opposite Ends)
  • LeetCode #75  — Sort Colors / Dutch National Flag (Partition)

Hard

  • LeetCode #42  — Trapping Rain Water (Opposite Ends)
  • LeetCode #16  — 3Sum Closest (Two Pointers inside a loop)
📌  Start from Easy. Solve each problem yourself first — only look at solutions after genuinely trying. That’s how the pattern gets into your muscle memory.

Quick Recap — Everything in One Place

ConceptSummary
What it isUsing two index variables instead of one to reduce nested loops
Why it mattersConverts O(n²) brute force to O(n) — critical for interviews
Variation 1Opposite Ends — left and right pointer moving inward
Variation 2Slow & Fast — same direction, different conditions
Variation 3Partition — group/separate elements in-place
When to useSorted array, pair/triplet problems, in-place modifications
Time ComplexityO(n) for all three variations
Space ComplexityO(1) — no extra space needed

Two Pointers is one of those patterns that once it clicks, you’ll never un-see it. Practice the problems above in order, and within a week it will feel completely natural.

📬  This is part of my ongoing DSA Patterns series on Daily Dev Notes. Next up: Sliding Window Pattern — subscribe to the newsletter so you don’t miss it.

1 thought on “Two Pointers Pattern in DSA — Complete Guide for Beginners”

Leave a Comment