Skip to content

What is the Two Pointers Technique?

Patterns·6 min read·code in python

Two pointers is an algorithmic pattern that uses two indices to traverse a data structure, usually an array or string, instead of one. The pointers move toward each other from opposite ends, or in the same direction at different speeds, letting you solve many problems in a single linear pass with constant extra space.

The core idea: two indices, one pass

Most beginners reach for nested loops when a problem involves comparing elements, check every element against every other, an O(n squared) sweep. The two pointers pattern replaces that with two indices that move through the data deliberately, so you visit each position roughly once. Instead of re-scanning the whole array to ask 'what pairs with element i?', you let the second pointer's position carry information about what you have already ruled out.

The trick is that each pointer moves in only one direction and never backtracks. Because neither index resets, the total number of steps is bounded by the length of the array. That is what turns a quadratic brute force into a linear scan.

Two shapes: converging and fast–slow

There are two common layouts. In the converging (opposite-ends) form, one pointer starts at index 0 and the other at the last index, and they walk toward each other until they meet. This suits pair-sum searches on sorted arrays, in-place reversal, and palindrome checks.

In the fast–slow (same-direction) form, both pointers start near the front but advance at different rates or under different conditions. A slow 'write' pointer trails a fast 'read' pointer to compact an array in place, removing duplicates or zeros, while a fast pointer moving two steps to a slow pointer's one detects cycles in a linked list (Floyd's algorithm). Watching the two indices crawl through the array step by step makes which shape you need click faster than reading the loop.

Why it works on sorted data

For pair-sum problems the converging pattern relies on order. When the array is sorted, the sum of the two ends tells you exactly which way to move: if the sum is too small, the only way to increase it is to move the left pointer right toward larger values; if it is too big, move the right pointer left. Each comparison eliminates one candidate for good, so a single pass suffices.

This is also why sorting is sometimes worth the O(n log n) cost up front: it unlocks the linear scan for problems like 3Sum, where you fix one element and two-point the rest. On unsorted data without that structure, a hash table is often the better tool.

The code

pythonFind a pair summing to target in a sorted array with converging pointers.

def two_sum_sorted(nums, target):
    left, right = 0, len(nums) - 1
    while left < right:
        current = nums[left] + nums[right]
        if current == target:
            return [left, right]
        if current < target:
            left += 1      # sum too small, need a larger value
        else:
            right -= 1     # sum too big, need a smaller value
    return [-1, -1]        # no pair found

Run it in the browser IDE, free on the platform. Open the IDE

Complexity

TimeO(n)
SpaceO(1)

A single scan is O(n) time and O(1) extra space because neither pointer backtracks. If the input must be sorted first, the sort's O(n log n) dominates. Nested two-pointer variants like 3Sum are O(n squared).

Watch it run

Reading the steps is one thing. Watching any of these move on your own input, one step at a time, is where the picture sticks.

When to use it

  • Searching a sorted array for a pair or triplet whose values meet a sum or difference condition
  • Reversing an array or string in place, or checking whether a string is a palindrome
  • Removing duplicates, zeros, or unwanted elements from a sorted array in place with a read/write pointer
  • Detecting a cycle or finding the midpoint of a linked list using fast and slow pointers

Watch out for

  • Applying the converging sum trick to unsorted data: the 'move left or right' logic only works when the array is sorted, and sorting first adds O(n log n).
  • Getting the loop condition wrong: using left <= right when an element must not pair with itself, or advancing the wrong pointer, which causes infinite loops or missed answers.
  • Forgetting to skip over duplicate values in problems like 3Sum, which produces repeated result tuples.

Two Pointers: questions we get

Is two pointers hard to learn?

No: it is one of the more approachable patterns once you see it move. The logic is just two indices that never backtrack, and it clicks quickly when you watch them step through an array frame by frame. The harder part is recognizing when a problem is a two-pointer problem, which comes with practice.

When should I use two pointers instead of a hash table?

Reach for two pointers when the data is sorted or you need O(1) extra space, such as in-place reversal or dedup. Use a hash table when the input is unsorted and you can afford O(n) memory to look up complements in one pass. For Two Sum on an unsorted array a hash map is usually simpler; on a sorted array two pointers wins on space.

What is the time complexity of two pointers?

The scan itself is O(n) time and O(1) extra space, because each pointer traverses the array at most once. If you must sort the input first to use the pattern, the total becomes O(n log n), dominated by the sort. Nested variants like 3Sum are O(n squared).

What is the difference between two pointers and sliding window?

Sliding window is a specialized two-pointer technique where both pointers move in the same direction and the span between them represents a contiguous subarray or substring. Plain two pointers is broader: the indices can start at opposite ends and converge. If you are tracking a running window like a max sum or longest substring, that is sliding window.

Related concepts

Reading is the easy part. In a batch you build it, say it out loud in a scored mock round and hear what an interviewer would think.

Talk to mentor