Skip to content
← All posts

Long Pressed Name: Two-Pointer Character Matching

6 min read
leetcodeproblemeasystringstwo-pointers

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.

namealextypedaaleexlong pressmatch
name = "alex", typed = "aaleex". Green cells match name characters. Yellow cells are extra characters from long presses. Dashed lines show the correspondence.

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:

  1. If name[i] == typed[j], the character matches. Advance both pointers.
  2. Else if typed[j] == typed[j - 1], the key was held down too long. This is a valid long press, so advance j only.
  3. Otherwise, you have a character in typed that cannot be explained by either matching or long-pressing. Return False.

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]

nameailextypedajaleex

name[0] = 'a' matches typed[0] = 'a'. Advance both pointers. i = 1, j = 1.

Step 2: Compare name[1] and typed[1]

namealiextypedaajleex

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]

namealiextypedaaljeex

name[1] = 'l' matches typed[2] = 'l'. Advance both. i = 2, j = 3.

Step 4: Compare name[2] and typed[3]

namealeixtypedaalejex

name[2] = 'e' matches typed[3] = 'e'. Advance both. i = 3, j = 4.

Step 5: Compare name[3] and typed[4]

namealexitypedaaleejx

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]

namealexitypedaaleexj

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:

  1. i and j start at the beginning of name and typed respectively. The outer loop runs until every character in typed has been consumed.
  2. If the current characters match (name[i] == typed[j]), both pointers advance. This means the character was typed correctly.
  3. If they do not match but typed[j] equals typed[j - 1], this is a long press repetition. Only j advances because i still needs to match a real character.
  4. If neither condition holds, the typed string has a character that cannot be explained. Return False immediately.
  5. After the loop, verify i == len(name). If i fell short, some characters in name were never matched.

Complexity analysis

MetricValue
TimeO(n + m), where n = len(name) and m = len(typed). Each pointer moves forward at each step, so at most n + m iterations.
SpaceO(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 with i = 2, but len(name) = 3. The final check i == len(name) returns False. Characters in name were never typed.
  • Extra characters at end that do not match name = "alex", typed = "aaleexa": after matching all of name, j continues. typed[5] = 'a' does not match typed[4] = 'x', so the long press condition fails. Returns False.
  • Empty name and empty typed name = "", typed = "": the while loop never executes, and i == len(name) is 0 == 0, which is True.
  • Empty name, non-empty typed name = "", typed = "a": i stays at 0. typed[0] = 'a' cannot match name[0] (out of bounds), and j > 0 is false, so we return False.
  • Single character repeated name = "a", typed = "aaa": first iteration matches, then two long presses. Returns True.
  • Completely different strings name = "abc", typed = "xyz": first character fails both conditions immediately. Returns False.

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

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.