
Python practice
Python two pointers practice questions
5 problems, ordered from easiest. They run in your browser, and 3 are free.
Start with Merge Two Sorted ListsOn this page13 sections
- The idea in a minute
- Why check every pair when you can be smarter
- Watch the pointers close in
- Why moving a pointer is safe
- The loop condition and the edges
- Another use: reverse in place
- Another use: is it a palindrome
- A different flavour: both pointers move the same way
- Merging two sorted lists
- When two pointers is the wrong tool
- Questions people ask
- Now try it yourself
- More Python topics
The idea in a minute
On a sorted list you do not have to check every pair. Put a finger at each end, look at the sum, and move the one that helps. You never go back, so it takes one pass.
The page shows why moving a pointer is safe, then uses the idea for pairs, reversing, palindromes, removing duplicates and merging sorted lists.
Why check every pair when you can be smarter
You have a sorted list and want two numbers that add up to a target. The first idea is a loop inside a loop: try every pair. With 1,000 numbers that is about half a million pairs. But the list is sorted, and that is a gift. It lets you rule out many pairs with a single look.
Put one finger on the smallest number and one on the biggest. Add them. Too small? The only way to get bigger is to move the left finger to a larger number. Too big? Move the right finger to a smaller number. You never go back. That is two pointers.
Watch the pointers close in
Target 13 in a sorted list
1a = [1, 3, 4, 6, 8, 9]2t = 133l, r = 0, len(a) - 14while l < r:5 s = a[l] + a[r]6 if s == t:7 print(l, r, a[l], a[r])8 break9 l, r = (l + 1, r) if s < t else (l, r - 1)
a = [1, 3, 4, 6, 8, 9]
t = 13
l, r = 0, len(a) - 1
while l < r:
s = a[l] + a[r]
if s == t:
print(l, r, a[l], a[r])
break
l, r = (l + 1, r) if s < t else (l, r - 1)2 5 4 9
Three steps, not fifteen. The line at the bottom, l, r = (l + 1, r) if s < t else (l, r - 1), is the whole strategy: too small moves the left pointer, too big moves the right one.
Why moving a pointer is safe
This is the part to understand, because it is the proof that you did not skip the answer. Say the sum of a[l] and a[r] is too small. Then a[l] paired with anything at or left of r gives something even smaller (the list is sorted, so everything left of r is smaller). That means a[l] can never be part of the answer, and it is safe to drop it.
Before you code a two pointers question, say: 'if the sum is too small I move ___, if it is too big I move ___.' If you cannot say it, two pointers is not the right tool, or the list needs sorting first.
The loop condition and the edges
def pair_with_sum(a, t):
l, r = 0, len(a) - 1
while l < r:
s = a[l] + a[r]
if s == t:
return (a[l], a[r])
if s < t:
l += 1
else:
r -= 1
return None
print(pair_with_sum([1, 3, 4, 6, 8, 9], 13))
print(pair_with_sum([1, 3, 4, 6, 8, 9], 100))
print(pair_with_sum([5], 10))
print(pair_with_sum([], 10))(4, 9) None None None
l < r (not l <= r) stops the pointers from meeting on the same item, because a number cannot be paired with itself. It also handles one item and an empty list for free: the loop just never starts.
Another use: reverse in place
Two pointers does not have to hunt for a target. Swap the ends and walk inward, and you have reversed the list without making a copy.
a = [1, 2, 3, 4, 5]
l, r = 0, len(a) - 1
while l < r:
a[l], a[r] = a[r], a[l]
l += 1
r -= 1
print(a)[5, 4, 3, 2, 1]
Another use: is it a palindrome
def is_palindrome(s):
l, r = 0, len(s) - 1
while l < r:
if s[l] != s[r]:
return False
l += 1
r -= 1
return True
print(is_palindrome("level"))
print(is_palindrome("lever"))True False
Same shape, different rule: if the two ends differ, stop with False. If the pointers meet, every pair matched.
A different flavour: both pointers move the same way
So far the pointers came from opposite ends. The other common setup has both starting at the left. A slow pointer marks where the next good item should go, and a fast pointer scans ahead. Removing duplicates from a sorted list is the classic case.
a = [1, 1, 2, 2, 2, 3, 4, 4]
slow = 0
for fast in range(1, len(a)):
if a[fast] != a[slow]:
slow += 1
a[slow] = a[fast]
unique = a[:slow + 1]
print(unique)[1, 2, 3, 4]
fast looks at every item. Whenever it finds something different from the last kept item, slow moves one step and keeps it. Everything at or before slow is the cleaned list, no extra list needed during the scan.
Merging two sorted lists
a = [1, 4, 7]
b = [2, 3, 9]
i = j = 0
merged = []
while i < len(a) and j < len(b):
if a[i] <= b[j]:
merged.append(a[i])
i += 1
else:
merged.append(b[j])
j += 1
merged += a[i:] + b[j:]
print(merged)[1, 2, 3, 4, 7, 9]
Take the smaller of the two front items, move that pointer. When one list runs out, add whatever is left of the other. This is the merge step of merge sort.
When two pointers is the wrong tool
- The list is not sorted and you cannot sort it (the positions matter). A dictionary is the usual answer, see the hashing topic.
- You need every pair, not just one. Two pointers finds one answer per pass.
- The condition is not monotonic: moving a pointer does not reliably make the sum bigger or smaller.
Questions people ask
Two pointers or hash map for two sum?
Sorted input and no extra memory wanted: two pointers. Unsorted input and you need the original positions: hash map.
Why does it take one pass?
Each step moves a pointer by one and never back, so the two of them together cover at most n steps.
Is it the same as a sliding window?
Related. A sliding window cares about everything between the two pointers (a running total of that block). Two pointers from opposite ends only care about the values at the two pointers.
Keep this checklist handy
- The list usually needs to be sorted first, or the moves have no meaning.
- Use l < r in the loop so the pointers never cross.
- Move exactly one pointer per step, or you can skip the answer.
Now try it yourself
5 two pointers problems. They run right here in your browser, and you can start anywhere.
Warm up
One idea at a time. Do these in order.
Getting comfortable
Two ideas together, or a trap to spot.
Want a guided order across every topic? Open the practice sheets or the Python hub.
More Python topics
Python
Strings
Slice, count and clean text
15 problemsPractice
Python
Dictionaries
Group and count by key
16 problemsPractice
Python
Hashing
Trade memory for a single pass
13 problemsPractice
Python
Arrays
Loop, accumulate, reverse
15 problemsPractice
Python
Two pointers
Walk in from both ends
You are here
Python
Sliding window
Slide once instead of re-adding
11 problemsPractice
Python
Sorting
Order by a key, then reason about neighbours
8 problemsPractice
Python
Stacks
Last in, first out
7 problemsPractice
Python
Recursion
A function that calls itself
8 problemsPractice