← back to blog
6 November 2026

Two Pointer pattern in simple words

DSA Two Pointers Arrays Linked List

Many array and string problems look like they need two loops. Often, they do not. If you use two pointers, you can solve them with just one pass. Here is how the pattern works, explained in plain words.

What is the Two Pointer pattern?

It is a technique where two variables, called pointers, move through a data structure at the same time. The data structure can be an array, a string or a linked list. The two pointers usually start from different positions.

A pointer is nothing special here. For an array or a string, it is just an index number like left = 0. For a linked list, it is a reference to a node.

Array 14329 String hello Linked list 1234
Two pointers work on linear data structures: arrays, strings and linked lists.

Three ways the pointers can move

There are only three movements to remember.

1. Towards each other

One pointer starts at the left end, the other at the right end. They move closer until they meet. This is the most common type.

12471115 leftright
Left moves right, right moves left, until they meet.

2. Away from each other

Both pointers start in the middle and move outwards, one to each side. This is useful when you want to grow something from a centre, like finding the longest palindrome around a point.

abccba leftright
Start from the middle and expand outwards.

3. Same direction (slow and fast)

Both pointers move the same way, but at different speeds or with different jobs. One is called slow and the other fast. This is used for removing duplicates, partitioning, and linked list problems.

112233 slowfast
Both go the same way. Fast explores, slow keeps the result.

Where is it used?

The pattern helps when a problem is about comparing, searching or partitioning elements. If you can say "I need to look at two positions at once", think of two pointers.

Why use two pointers?

racecar Compare from both ends. All pairs match, so it is a palindrome.
Palindrome check: compare the outer letters first, then move inwards.

Template 1: one input, pointers from both ends

Use this when you have one array or string and the two pointers move towards each other.

a = [1, 4, 3, 2, 9]
left = 0
right = a.length - 1

while left < right:
    if CONDITION:
        left = left + 1
    else:
        right = right - 1

return ans

The loop runs while left < right. In each step, the condition tells you which pointer to move. Every step moves one pointer, so the loop can run at most n times.

Example: pair sum in a sorted array

Find two numbers that add up to a target. The array is sorted: [1, 2, 4, 7, 11, 15] and the target is 15.

left = 0
right = a.length - 1

while left < right:
    sum = a[left] + a[right]
    if sum == target:
        return [left, right]
    if sum < target:
        left = left + 1      # need a bigger sum
    else:
        right = right - 1    # need a smaller sum

return not found
StepleftrightSumWhat we do
111516Too big, move right back
211112Too small, move left forward
321113Too small, move left forward
441115Match. Done.

Because the array is sorted, we know exactly which pointer to move. We never check a pair twice. A normal nested loop would check every pair, which is O(n²). Two pointers does it in O(n).

Pair sum like this needs a sorted array. If the array is not sorted, sort it first, or use a different approach.

Template 2: two inputs, go until both are finished

Use this when you have two arrays (or two strings). You keep one pointer on each, and you move forward until both are fully used.

a = [1, 4, 7]
b = [2, 3, 9, 10]

i = 0
j = 0

while i < a.length AND j < b.length:
    if CONDITION:        # e.g. a[i] <= b[j]
        use a[i]
        i = i + 1
    else:
        use b[j]
        j = j + 1

# one array may still have items left
while i < a.length:
    use a[i]
    i = i + 1

while j < b.length:
    use b[j]
    j = j + 1

The first loop stops when one array runs out. The two small loops after it take care of whatever is left in the other. This is how you merge two sorted arrays: at each step, pick the smaller value and move that pointer. The result is [1, 2, 3, 4, 7, 9, 10].

Template 3: same direction, slow and fast

Here both pointers start at the beginning (or at the head of a list). Fast goes ahead and looks at each element. Slow stays behind and marks where the next good value should be placed.

Example: remove duplicates from a sorted array

slow = 0

for fast = 1 to a.length - 1:
    if a[fast] != a[slow]:
        slow = slow + 1
        a[slow] = a[fast]

return slow + 1     # length of the array without duplicates

For [1, 1, 2, 2, 3, 3], the array becomes [1, 2, 3, ...] and the answer is 3. We did it in place, with no extra array.

Example: linked list

For linked lists, slow moves one node at a time and fast moves two nodes at a time.

slow = head
fast = head

while fast != null AND fast.next != null:
    slow = slow.next
    fast = fast.next.next
    if slow == fast:
        return true      # cycle found

return false

How to know when to use it

Ask yourself these questions:

  1. Is the data an array, a string or a linked list?
  2. Do I need to compare or combine two positions?
  3. Is the data sorted, or can I sort it?
  4. Am I about to write two nested loops over the same data?

If the answer is yes to most of these, try two pointers.

Practice problems

These are good to try, in this order:

Summary

Two pointers is a simple idea: use two positions instead of one, and let them help each other. Move them towards each other, away from each other, or in the same direction. Most of the time, you turn a slow O(n²) solution into a fast O(n) one, and you do not need any extra memory.

Pick one problem from the list above and solve it today. After two or three, you will start to spot the pattern on your own.