Back to DSA Guide Catalog

Algorithmmedium

Two Pointers Complete Guide

Two-pointer techniques use two moving indices to avoid expensive nested loops.

Common variants: opposite-direction pointers on sorted data, same-direction window pointers, or slow/fast pointers for cycle/middle logic.

The core skill is defining how each pointer moves when a condition is true/false.

Typical Complexity Baseline

MetricValue
Typical traversalO(n)

Video Explainer

Prefer video learning? This explainer gives a quick visual walkthrough of the core idea before you dive into the detailed sections below.

Two Pointers Visualizer

Track left/right pointers moving toward each other to satisfy a condition.

Two Pointers VisualizerStep 1 / 3

Start from both ends of sorted values.

Values

[1, 2, 3, 4, 6, 8, 11]

Target Sum

10

Pointers

left=0 (1), right=6 (11)

Decision

1 + 11 = 12 too large, move right leftward.

Core Concepts

Learn the core building blocks and terminology in one place before comparisons, so the mechanics are clear and duplicates are removed.

Left pointer

What it is: Tracks lower/start boundary.

Why it matters: Left pointer is a required building block for understanding how Two Pointers stays correct and performant on large inputs.

Right pointer

What it is: Tracks upper/end boundary.

Why it matters: Right pointer is a required building block for understanding how Two Pointers stays correct and performant on large inputs.

Movement rule

What it is: Condition deciding which pointer advances.

Why it matters: Movement rule is a required building block for understanding how Two Pointers stays correct and performant on large inputs.

Invariant

What it is: Property that remains true while pointers move.

Why it matters: Invariant is a required building block for understanding how Two Pointers stays correct and performant on large inputs.

Termination rule

What it is: Stop condition such as left >= right.

Why it matters: Termination rule is a required building block for understanding how Two Pointers stays correct and performant on large inputs.

Opposite-direction

What it is: Pointers start at both ends and move inward.

Why it matters: Pointers start at both ends and move inward. In Two Pointers, this definition helps you reason about correctness and complexity when inputs scale.

Same-direction

What it is: Both pointers advance through sequence with different roles.

Why it matters: Both pointers advance through sequence with different roles. In Two Pointers, this definition helps you reason about correctness and complexity when inputs scale.

Fast/slow

What it is: One pointer moves faster to detect structure properties.

Why it matters: One pointer moves faster to detect structure properties. In Two Pointers, this definition helps you reason about correctness and complexity when inputs scale.

Window shrink

What it is: Move left pointer to restore constraint validity.

Why it matters: Move left pointer to restore constraint validity. In Two Pointers, this definition helps you reason about correctness and complexity when inputs scale.

Stable partition

What it is: Rearrange while preserving order in selected partitions.

Why it matters: Rearrange while preserving order in selected partitions. In Two Pointers, this definition helps you reason about correctness and complexity when inputs scale.

Putting It All Together

This walkthrough connects the core concepts of Two Pointers into one end-to-end execution flow.

Step 1

Left pointer

Tracks lower/start boundary.

Before

Sorted

124711
  • target = 15
  • left=0, right=4

After

  • left=1, right=4
  • Candidate sum increases

Transition

sum=1+11=12 < 15
Move left pointer right

Why this step matters: Left pointer is a required building block for understanding how Two Pointers stays correct and performant on large inputs.

Step 2

Right pointer

Tracks upper/end boundary.

Before

  • left=1 (2), right=4 (11)
  • sum=13 < 15

After

  • left=2 (4), right=4 (11)
  • sum=15 found

Transition

Advance left pointer again
Recompute with larger left value

Why this step matters: Right pointer is a required building block for understanding how Two Pointers stays correct and performant on large inputs.

Step 3

Movement rule

Condition deciding which pointer advances.

Before

  • String: "abca"
  • left=0, right=3

After

  • Mismatch at b vs c
  • Palindrome = false

Transition

Compare chars at both pointers
Move inward when equal

Why this step matters: Movement rule is a required building block for understanding how Two Pointers stays correct and performant on large inputs.

Step 4

Invariant

Property that remains true while pointers move.

Before

Container heights

186254837
  • left and right bound current area

After

  • Area candidate improved
  • Single pass O(n)

Transition

Keep taller side, move shorter side
Seek potential larger area

Why this step matters: Invariant is a required building block for understanding how Two Pointers stays correct and performant on large inputs.

How It Compares

vs Hash map lookup

When to choose this: Choose two pointers when sorted order already exists.

Tradeoff: Hash map can avoid sort precondition but uses extra memory.

vs Sliding window

When to choose this: Choose two pointers for pair relation constraints.

Tradeoff: Sliding window is stronger for range constraints on contiguous data.

vs Brute force nested loops

When to choose this: Choose two pointers for linear progress through data.

Tradeoff: Requires clear movement logic; brute force is simpler but slower.

Real-World Stories and Company Examples

Pinterest

Recommendation dedup and content curation pipelines use two-pointer merges over sorted candidate sets.

Takeaway: Linear pointer scans scale well in ranking pipelines.

Datadog

Time-series merge/join tasks use pointer-based passes on sorted timestamps.

Takeaway: Two-pointer traversal avoids heavy random access during stream processing.

Snowflake

Sorted block merge operations during query processing use pointer-driven loops.

Takeaway: Pointer discipline is central to efficient sorted-data operations.

Implementation Guide

Move shorter side inward because area is limited by min(heightLeft, heightRight).

Complexity: Time O(n), Space O(1)

Container with most water style scan

function maxArea(heights: number[]): number {
  let leftIndex = 0
  let rightIndex = heights.length - 1
  let bestArea = 0

  while (leftIndex < rightIndex) {
    const width = rightIndex - leftIndex
    const area = width * Math.min(heights[leftIndex], heights[rightIndex])
    bestArea = Math.max(bestArea, area)

    if (heights[leftIndex] < heights[rightIndex]) leftIndex += 1
    else rightIndex -= 1
  }

  return bestArea
}

Common Problems and Failure Modes

  • Moving both pointers when only one should move.
  • Forgetting to sort input when algorithm assumes sorted order.
  • Incorrect duplicate handling causing repeated results.
  • Missing termination condition leading to infinite loops.
  • Mutating shared pointers across helper functions without clear ownership.

Tips and Tricks

  • Two pointers are strongest when movement rules are deterministic.
  • If one pointer moves backward frequently, you may need a different pattern.
  • In sorted arrays, move pointer that causes current comparison failure.
  • Name pointers semantically (leftIndex, rightIndex) to reduce mistakes.

When to Use

Use these signals to decide if this data structure/algorithm is the right fit before implementation.

Real-system usage signals

  • Converts many O(n^2) scans into O(n) or O(n log n) workflows.
  • Works naturally with sorted arrays and string windows.
  • Keeps memory overhead low with in-place traversal.

LeetCode-specific tips (including pattern-identification signals)

  • Identification signal: two positions move under deterministic rules (often from both ends or slow/fast patterns).
  • Identification signal: sorted data with pair/triplet target checks can avoid nested loops by moving pointers based on sum comparison.
  • If you can decide pointer movement from current comparison only, two-pointers is usually a fit.
  • For Two Pointers questions, start by naming the core invariant before writing code.
  • Use the constraint section to set time/space target first, then pick the data structure/algorithm.
  • Solve one tiny example by hand and map each transition to your variables before implementing.
  • Run adversarial cases: empty input, duplicates, max-size input, and sorted/reverse patterns when relevant.
  • During interviews, explain why your approach is the right pattern for this prompt, not just why the code works.

LeetCode Progression (Easy to Hard)

Back to DSA Guide Catalog
#ProblemDifficultyTypical Complexity
1Valid PalindromeEasyO(n)
2Merge Sorted ArrayEasyO(n+m)
3Remove Duplicates from Sorted ArrayEasyO(n)
4Two Sum IIMediumO(n)
5Container With Most WaterMediumO(n)
63SumMediumO(n^2)
7Sort ColorsMediumO(n)
8Trapping Rain WaterHardO(n)
9Minimum Window SubstringHardO(n)
10Substring with Concatenation of All WordsHardO(n*k)