A string is just a sequence of characters — "HELLO" is H, E, L, L, O in a row. Many string problems are solved with the two-pointer trick: put one finger at each end and walk them toward the middle. Reversing a string is the cleanest example, so we will start there.
Put a pointer l at the start and a pointer r at the end. Swap the characters they point at, then
move l one step right and r one step left. Repeat until they meet — the string is now reversed,
and you never used a second copy.
Intuition
Imagine a row of lettered cards on a table and you want them in reverse order. You do not pick them all up and re-deal them. Instead you swap the outermost pair — first card with last card — then the next pair in, then the next, working your way toward the center. The two cards in the middle (or the single middle card, for an odd length) end up exactly where they started. That inward march of two pointers is the whole algorithm.
Walk through it
Step through the animation on the right. We reverse "HELLO" into "OLLEH". The pointer l starts on the first cell and r on the last. At each turn the two cells they point at turn blue (we are looking at this pair), then turn and slide past each other — that is the swap. Once swapped, the two ends turn green and are locked: they are in their final positions and will never move again.
After the first swap the ends H and O trade places. The pointers step inward, E and L swap, and the pointers step inward once more. Now l and r have crossed, so the loop stops. The middle L never had to move. Five characters, just two swaps.
The code, line by line
def reverse(s):
# strings are immutable, so work on a list of chars
chars = list(s)
l, r = 0, len(chars) - 1
while l < r:
chars[l], chars[r] = chars[r], chars[l]
l += 1
r -= 1
return "".join(chars)- In Python a string cannot be changed in place —
s[0] = "X"is an error. So we copy it into alistof characters, do the work there, and"".join(...)it back at the end. l, r = 0, len(chars) - 1puts the two pointers on the first and last slots.- Line 5,
while l < r, is the loop condition. The moment the pointers meet or cross, we are done — every pair has been swapped. - Line 6 is the swap, the heart of the trick. Python swaps two values in one line by assigning the pair in reverse.
l += 1andr -= 1march the pointers inward so the next turn handles the next pair.
The palindrome twin
The same two-pointer skeleton checks whether a string is a palindrome (reads the same forward and backward). The only change is line 6: instead of swapping the two ends, you compare them.
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 TrueIf any outer pair differs, it is not a palindrome and you can bail out immediately. If the pointers meet without a mismatch, every mirrored pair matched — it is a palindrome.
Complexity
| Case | Time | Notes |
|---|---|---|
| Reverse / palindrome check | O(n) (moderate) | each pointer touches each char once |
O(1) (fast)The two pointers together visit every character exactly once, so the time is O(n). The reverse-a-Python-string version needs an O(n) list copy because strings are immutable, but the swapping itself uses only a couple of index variables — O(1) extra space. If you are handed a mutable list of characters directly (a common interview setup), the reverse is genuinely in place at O(1) space.
When to use / pitfalls
Two pointers from opposite ends is the go-to pattern for "reverse it", "is it a palindrome", and "find a pair in a sorted array that sums to a target". The signal: you are comparing or pairing the front with the back and can move both ends inward. Mention that strings are immutable in Python and that you convert to a list — interviewers like that detail.
Get the loop condition right: it is while l < r, not l <= r. With <=, when l and r land on
the same middle character you would swap it with itself — harmless for a reverse, but wasted work, and
for other two-pointer problems an off-by-one here is a real bug.
Practice
Reversing 'HELLO' with two pointers, how many swaps actually happen before the loop stops?
1. Why does the Python reverse copy the string into a list first?
2. What is the loop condition for the two-pointer reverse?
3. How would you turn this reverse into a palindrome check?
4. What is the time complexity of the two-pointer reverse?