Algorithms

Mastering Two Pointers: A Step-by-Step Guide to Solving Sequence Problems

Learn the Two Pointers algorithm pattern with step-by-step explanations, Elixir examples, manual traces, and beginner-friendly exercises.

In this article
  1. What Kind of Problems Does Two Pointers Solve?
  2. The Core Idea
  3. When Should You Think About Two Pointers?
  4. Common Two Pointers Strategies
  5. 1. Opposite Direction Pointers
  6. 2. Same Direction Pointers
  7. 3. Fast and Slow Pointers
  8. Step-by-Step Method
  9. Step 1: Understand the Input
  10. Step 2: Decide Where the Pointers Start
  11. Step 3: Write the Movement Rules
  12. Step 4: Trace the Example by Hand
  13. Step 5: Write the Code
  14. Example: Valid Palindrome
  15. How to Practice Two Pointers
  16. Exercises
  17. Exercise 1: Valid Palindrome
  18. Exercise 2: Reverse List
  19. Exercise 3: Two Sum II
  20. Exercise 4: Move Zeroes
  21. Exercise 5: Container With Most Water
  22. Final Checklist

Two Pointers is an algorithmic pattern used to solve problems by tracking two positions in a sequence at the same time.

A sequence can be:

  • an array;
  • a list;
  • a string;
  • a linked list.

Instead of checking every possible combination with nested loops, the Two Pointers pattern moves two pointers through the data using a clear rule.

This often improves a solution from O(n^2) to O(n).

What Kind of Problems Does Two Pointers Solve?

Two Pointers is useful when a problem asks you to work with two positions inside the same sequence.

It commonly solves problems like:

  • finding two numbers that match a condition;
  • checking if a string is a palindrome;
  • reversing a string or list;
  • moving values inside an array;
  • removing duplicates from a sorted array;
  • comparing values from both ends;
  • working with sorted arrays;
  • detecting cycles in linked lists.

The most important idea is:

Every time you move a pointer, you must know why that move is safe.

The Core Idea

A Two Pointers solution usually follows this structure:

  1. Create a left pointer.
  2. Create a right pointer.
  3. Compare the values at both pointers.
  4. Decide which pointer should move.
  5. Repeat until you find the answer or the pointers meet.

Example:

[2, 7, 11, 15]
L R

Here:

  • L points to the beginning;
  • R points to the end.

When Should You Think About Two Pointers?

Ask yourself these questions:

  1. Is the input a sequence?
  2. Do I need to compare two values?
  3. Is the sequence sorted?
  4. Am I looking for a pair?
  5. Do I need to reverse something?
  6. Do I need to move values in-place?
  7. Can I discard part of the search space after each comparison?

If the answer is yes to some of these questions, Two Pointers may be useful.

Common Two Pointers Strategies

1. Opposite Direction Pointers

One pointer starts at the beginning.

The other pointer starts at the end.

[1, 2, 3, 4, 5]
L R

This is useful for:

  • palindrome checks;
  • reversing arrays;
  • sorted Two Sum;
  • container with most water.

2. Same Direction Pointers

Both pointers move from left to right.

[0, 1, 0, 3, 12]
R
W

Usually:

  • one pointer reads values;
  • the other pointer writes or tracks valid positions.

This is useful for:

  • moving zeroes;
  • removing duplicates;
  • filtering values.

3. Fast and Slow Pointers

One pointer moves faster than the other.

slow -> moves 1 step
fast -> moves 2 steps

This is useful for:

  • detecting cycles;
  • finding the middle of a linked list;
  • removing the nth node from the end.

Step-by-Step Method

Use this process when solving a Two Pointers problem.

Step 1: Understand the Input

Ask:

What is the sequence?

Example:

numbers = [2, 7, 11, 15]

The sequence is a list of numbers.

Step 2: Decide Where the Pointers Start

For a sorted array pair problem:

left = 0
right = length - 1

Example:

[2, 7, 11, 15]
L R

Step 3: Write the Movement Rules

Before coding, write the rules in plain English.

For Two Sum II:

If sum == target, return the answer.
If sum < target, move the left pointer to the right.
If sum > target, move the right pointer to the left.

Step 4: Trace the Example by Hand

Example:

numbers = [2, 7, 11, 15]
target = 9

Trace:

left = 0, right = 3
2 + 15 = 17
17 is greater than 9
Move right left
left = 0, right = 2
2 + 11 = 13
13 is greater than 9
Move right left
left = 0, right = 1
2 + 7 = 9
Found the answer

Answer:

[1, 2]

Step 5: Write the Code

Example in Elixir:

defmodule Solution do
@spec two_sum([integer()], integer()) :: [integer()]
def two_sum(numbers, target) do
values = List.to_tuple(numbers)
search(values, target, 0, tuple_size(values) - 1)
end
defp search(values, target, left, right) do
sum = elem(values, left) + elem(values, right)
cond do
sum == target ->
[left + 1, right + 1]
sum < target ->
search(values, target, left + 1, right)
sum > target ->
search(values, target, left, right - 1)
end
end
end

Example: Valid Palindrome

Problem:

Given a string, return true if it reads the same forward and backward.

Example:

"level"

Expected output:

true

Pointer idea:

l e v e l
L R

Rules:

If characters are different, return false.
If characters are equal, move both pointers inward.
If pointers meet or cross, return true.

Elixir solution:

defmodule Solution do
@spec palindrome?(String.t()) :: boolean()
def palindrome?(s) do
chars = s |> String.graphemes() |> List.to_tuple()
check(chars, 0, tuple_size(chars) - 1)
end
defp check(_chars, left, right) when left >= right, do: true
defp check(chars, left, right) do
if elem(chars, left) == elem(chars, right) do
check(chars, left + 1, right - 1)
else
false
end
end
end

Trace:

"level"
left = 0, right = 4
l == l
left = 1, right = 3
e == e
left = 2, right = 2
stop
true

How to Practice Two Pointers

Follow this routine:

  1. Read the problem.
  2. Identify the sequence.
  3. Choose where each pointer starts.
  4. Write the movement rules in English.
  5. Trace one example manually.
  6. Write the code.
  7. Test with small inputs.
  8. Explain why each pointer movement is safe.

Do not jump straight to code.

The pointer movement is the most important part.

Exercises

Exercise 1: Valid Palindrome

Input:

"racecar"

Expected output:

true

Practice:

  • Start one pointer at the beginning.
  • Start one pointer at the end.
  • Compare both characters.
  • Move inward when they match.

Extra tests:

"level" -> true
"hello" -> false
"a" -> true

Exercise 2: Reverse List

Input:

[1, 2, 3, 4, 5]

Expected output:

[5, 4, 3, 2, 1]

Practice:

  • Start one pointer at the beginning.
  • Start one pointer at the end.
  • Swap both values.
  • Move both pointers inward.

Extra tests:

[] -> []
[1] -> [1]
[1, 2] -> [2, 1]

Exercise 3: Two Sum II

Input:

numbers = [2, 7, 11, 15]
target = 9

Expected output:

[1, 2]

Practice:

  • Use a sorted array.
  • Move the left pointer when the sum is too small.
  • Move the right pointer when the sum is too large.

Extra tests:

[1, 2, 3, 4, 6], target = 6 -> [2, 4]
[2, 3, 4], target = 6 -> [1, 3]
[-1, 0], target = -1 -> [1, 2]

Exercise 4: Move Zeroes

Input:

[0, 1, 0, 3, 12]

Expected output:

[1, 3, 12, 0, 0]

Practice:

  • Use one pointer to read.
  • Use another pointer to track where the next non-zero value should go.
  • Keep the original order of non-zero values.

Extra tests:

[0] -> [0]
[1, 0] -> [1, 0]
[0, 0, 1] -> [1, 0, 0]

Exercise 5: Container With Most Water

Input:

[1, 8, 6, 2, 5, 4, 8, 3, 7]

Expected output:

49

Practice:

  • Start with the widest container.
  • Calculate the current area.
  • Move the pointer with the smaller height.
  • Keep the best area found.

Key idea:

The shorter side limits the area.
Move the shorter side because it is the only side that can improve the result.

Final Checklist

Before using Two Pointers, answer:

  1. Where does the left pointer start?
  2. Where does the right pointer start?
  3. What does each pointer represent?
  4. What condition moves the left pointer?
  5. What condition moves the right pointer?
  6. When does the algorithm stop?
  7. Why is each pointer movement safe?
  8. What is the time complexity?
  9. What is the space complexity?

If you can answer these questions, you understand the pattern.