Two Pointers
- Pronunciation
- TOO POYN-terz
In short
The two pointers technique walks an array or list with two indexes moved by simple rules, turning many problems that seem to need nested loops into one pass.
What is the two pointers technique?
A classic example is finding two numbers in a sorted array that add up to a target. Checking every pair takes O(n²) time. With two pointers, one starts at the left end and one at the right: if their sum is too small, move the left pointer right; if too big, move the right pointer left. Each step rules out many pairs at once, and the answer is found in one O(n) pass.
Pointers can also move in the same direction at different speeds. With fast and slow pointers, also called the tortoise and hare, the fast one moves two steps for every one of the slow one; in a linked list with a cycle they eventually meet, which is Floyd's cycle detection algorithm, and when the fast pointer reaches the end, the slow one is at the middle.
Other common uses include removing duplicates from a sorted array in place, reversing an array or string, merging two sorted lists, checking whether a string is a palindrome, and partitioning an array around a value as quicksort does. Most of these use O(1) extra memory, since they only keep a couple of indexes.
A common misconception is that two pointers works on any array. The opposite-ends version relies on the data being sorted, or on another rule that tells you which pointer to move. Without that, you can't safely skip pairs, and a hash map or a different approach is needed.
Key takeaways
- Two pointers scan a sequence with two indexes in one pass.
- Opposite-end pointers solve pair problems in sorted arrays in O(n).
- Fast and slow pointers find cycles and the middle of linked lists.
- It usually needs only O(1) extra memory.
- It depends on sorted data or a rule for which pointer to move.
Example
def pair_with_sum(nums, target):
left, right = 0, len(nums) - 1
while left < right:
total = nums[left] + nums[right]
if total == target:
return nums[left], nums[right]
if total < target:
left += 1 # need a bigger sum
else:
right -= 1 # need a smaller sum
return None
def is_palindrome(text):
chars = [c.lower() for c in text if c.isalnum()]
i, j = 0, len(chars) - 1
while i < j:
if chars[i] != chars[j]:
return False
i, j = i + 1, j - 1
return True
print(pair_with_sum([1, 3, 4, 6, 9, 11], 13)) # (4, 9)
print(is_palindrome("Was it a car or a cat I saw?")) # TrueReaders ask
When should I use the two pointers technique?
When a problem involves pairs, ranges or comparisons in a sorted array or a linked list, and a brute-force solution would use nested loops. It often reduces O(n²) to O(n).
What is the difference between two pointers and sliding window?
A sliding window is a special case of two pointers where both move in the same direction and the elements between them form a window whose contents you track, such as a running sum.
What is Floyd's cycle detection?
An algorithm that detects a loop in a linked list with a slow pointer moving one step and a fast pointer moving two. If there is a cycle, the fast pointer eventually catches up with the slow one.
See also
- Sliding WindowData Structures, p. 29The sliding window technique solves problems on contiguous parts of an array or string by updating a window as it slides instead of recomputing each subarray.
- ArrayProgramming Fundamentals, p. 3An array is an ordered collection of values stored under one name, where each item is accessed by its numeric position, called an index, usually starting at 0.
- Linked ListData Structures, p. 22A linked list is a data structure that stores items in separate nodes, where each node holds a value and a reference to the next node in the chain.
- Binary SearchData Structures, p. 5Binary search is an algorithm that finds a value in a sorted list by repeatedly halving the search range, taking O(log n) time instead of checking every item.
- Big O NotationProgramming Fundamentals, p. 6Big O notation describes how an algorithm's running time or memory use grows as its input gets larger, focusing on the growth rate rather than exact speed.
- QuicksortData Structures, p. 27Quicksort is a divide and conquer sorting algorithm that partitions items around a chosen pivot, then sorts the smaller and larger groups the same way.
Spotted a mistake or something missing on this page?Suggest an edit