Long Pressed Name: Two-Pointer Character Matching
Your friend is typing their name on a keyboard. Sometimes a key is held down too long, causing a character to repeat. Given two strings name and typed, determine whether typed could be the result of this long-press behavior when typing name.
This is LeetCode 925: Long Pressed Name, an easy problem that teaches you how to use two pointers to match characters across two strings with different lengths. The core idea is that every character in typed must either advance forward in name or be a repeat of the previous key that was held too long.
Why this problem matters
Long Pressed Name is a clean introduction to the two-pointer technique on strings. Unlike problems where both strings must match character by character, here you need to handle "extra" characters that are valid only under a specific condition. This trains you to think about what makes a mismatch acceptable versus what makes it a failure.
The same reasoning applies to problems like Expressive Words (where characters can stretch by a factor), Backspace String Compare (where characters can be deleted), and Is Subsequence (where characters can be skipped). In all of these, two pointers walk at different speeds through two sequences, and a set of rules dictates when to advance each pointer.
The approach
You maintain two pointers: i for the current position in name and j for the current position in typed. At each step, you check:
- If
name[i] == typed[j], the character matches. Advance both pointers. - Else if
typed[j] == typed[j - 1], the key was held down too long. This is a valid long press, so advancejonly. - Otherwise, you have a character in
typedthat cannot be explained by either matching or long-pressing. ReturnFalse.
After the loop ends, check that i has reached the end of name. If it has not, there are characters in name that were never typed at all.
The second condition is what makes this problem interesting. A repeated character is only valid if it matches the character that came before it in typed. This prevents false positives like name = "ab" with typed = "ba".
Walking through it step by step
Let's trace through name = "alex" and typed = "aaleex" to see how the two pointers handle matches and long presses.
Step 1: Compare name[0] and typed[0]
name[0] = 'a' matches typed[0] = 'a'. Advance both pointers. i = 1, j = 1.
Step 2: Compare name[1] and typed[1]
name[1] = 'l' does not match typed[1] = 'a'. But typed[1] == typed[0] (long press). Advance j only. i = 1, j = 2.
Step 3: Compare name[1] and typed[2]
name[1] = 'l' matches typed[2] = 'l'. Advance both. i = 2, j = 3.
Step 4: Compare name[2] and typed[3]
name[2] = 'e' matches typed[3] = 'e'. Advance both. i = 3, j = 4.
Step 5: Compare name[3] and typed[4]
name[3] = 'x' does not match typed[4] = 'e'. But typed[4] == typed[3] (long press). Advance j only. i = 3, j = 5.
Step 6: Compare name[3] and typed[5]
name[3] = 'x' matches typed[5] = 'x'. Advance both. i = 4, j = 6. Both strings fully consumed. i == len(name), so return True.
Both pointers reached the end of their respective strings. Since i == len(name), every character in the name was accounted for, and every extra character in typed was a valid long press. The answer is True.
The two-pointer solution
def isLongPressedName(name, typed):
i = 0
j = 0
while j < len(typed):
if i < len(name) and name[i] == typed[j]:
i += 1
j += 1
elif j > 0 and typed[j] == typed[j - 1]:
j += 1
else:
return False
return i == len(name)
Here is what each piece does:
iandjstart at the beginning ofnameandtypedrespectively. The outer loop runs until every character intypedhas been consumed.- If the current characters match (
name[i] == typed[j]), both pointers advance. This means the character was typed correctly. - If they do not match but
typed[j]equalstyped[j - 1], this is a long press repetition. Onlyjadvances becauseistill needs to match a real character. - If neither condition holds, the typed string has a character that cannot be explained. Return
Falseimmediately. - After the loop, verify
i == len(name). Ififell short, some characters innamewere never matched.
Complexity analysis
| Metric | Value |
|---|---|
| Time | O(n + m), where n = len(name) and m = len(typed). Each pointer moves forward at each step, so at most n + m iterations. |
| Space | O(1), only two integer pointers. |
This is optimal. You must read every character in both strings at least once to verify the match.
Building blocks
This problem is built on two reusable patterns that CodeBricks drills independently.
1. Two-pointer traversal on strings
The pattern of walking two pointers through two sequences at potentially different speeds:
i, j = 0, 0
while j < len(second):
if match_condition(first, i, second, j):
i += 1
j += 1
elif skip_condition(second, j):
j += 1
else:
return False
return i == len(first)
In Long Pressed Name, the skip condition is "same as previous character." In Is Subsequence, there is no skip condition for the first string, only for the second. In Backspace String Compare, you preprocess to skip deleted characters. The skeleton is always the same: two pointers, conditional advancement, final check.
2. Character-level validation
The pattern of checking whether each character in a sequence satisfies a local constraint:
for j in range(len(sequence)):
if valid_match(j):
advance_primary()
elif valid_skip(j):
continue
else:
return False
In Long Pressed Name, the local constraint is "matches the expected character OR repeats the previous." In Valid Parentheses, the local constraint is "opens a bracket OR closes the most recent one." The structure is the same: process each element, check local rules, fail fast on violations.
The two-pointer approach works here because both strings are processed left to right with no backtracking. Each pointer only moves forward. If you ever needed to revisit earlier characters, you would need a different technique (like a stack or DP).
Edge cases
Before submitting, make sure your solution handles these:
- Typed is shorter than name
name = "abc", typed = "ab": the loop ends withi = 2, butlen(name) = 3. The final checki == len(name)returnsFalse. Characters in name were never typed. - Extra characters at end that do not match
name = "alex", typed = "aaleexa": after matching all of name,jcontinues.typed[5] = 'a'does not matchtyped[4] = 'x', so the long press condition fails. ReturnsFalse. - Empty name and empty typed
name = "", typed = "": the while loop never executes, andi == len(name)is0 == 0, which isTrue. - Empty name, non-empty typed
name = "", typed = "a":istays at 0.typed[0] = 'a'cannot matchname[0](out of bounds), andj > 0is false, so we returnFalse. - Single character repeated
name = "a", typed = "aaa": first iteration matches, then two long presses. ReturnsTrue. - Completely different strings
name = "abc", typed = "xyz": first character fails both conditions immediately. ReturnsFalse.
The two-pointer solution handles all of these without special-case logic.
From understanding to recall
You have read the two-pointer solution and it makes sense. Two pointers, two conditions, one final check. Clean. But can you write it from scratch in an interview without looking at it?
The details matter: checking i < len(name) before accessing name[i], verifying j > 0 before comparing typed[j] to typed[j - 1], and the final return i == len(name) instead of just True. These are small but critical, and they are easy to get wrong under pressure if you have not practiced writing them from memory.
Spaced repetition closes that gap. You practice writing the two-pointer character matching loop from scratch at increasing intervals. After a few rounds, the pattern is automatic. You see "verify characters match with allowed repetitions" and the code flows out without hesitation.
The two-pointer validation pattern is one of roughly 60 reusable building blocks that cover hundreds of LeetCode problems. Learning them individually and drilling them with spaced repetition is far more effective than grinding random problems and hoping they stick.
Related posts
- Expressive Words - Similar two-pointer matching where characters can stretch by a minimum factor
- Backspace String Compare - Two-pointer comparison with character deletion logic
- Is Subsequence - Two pointers checking if one string is a subsequence of another
CodeBricks breaks the long pressed name LeetCode problem into its two-pointer traversal and character validation building blocks, then drills them independently with spaced repetition. You type each piece from scratch until the pattern is automatic. When a character matching question shows up in your interview, you do not think about it. You just write it.