When can you use the two pointers technique, and what makes a problem a good candidate for it?
Two pointers works when the array is already ordered and a comparison can eliminate a whole region of the search space. If the input is sorted, then knowing the relationship between two values tells you something about every element between them, and you can discard that region permanently instead of testing it. Problems involving sorted arrays, palindromes, or finding a pair with a given sum are the classic cases.
def is_palindrome(text):
left, right = 0, len(text) - 1
while left < right:
if text[left] != text[right]:
return False
left += 1
right -= 1
return True
print(is_palindrome("racecar"))
print(is_palindrome("python"))The palindrome check is the purest example. The two pointers walk towards each other from the ends, and a single mismatch disproves the whole claim, so the function returns early. It is O of n time and O of 1 space, and it never allocates a reversed copy of the string, which is how the naive solution usually starts.
What disqualifies a problem is the absence of a monotonic rule. If the array is unsorted, a comparison between two elements tells you nothing about the elements in between, so you cannot discard them and the technique collapses into a quadratic scan. Another disqualifier is when the relationship between the two pointers depends on the whole history rather than on the current values.
The trade-off to mention is that two pointers is a space optimisation of a quadratic search, and it is only available when the data already carries the order you need. If you would have to sort first, the O of n log n sort and the extra copy often cost more than the map-based approach that solves the same problem in linear time with no precondition.