925. Long Pressed Name
Problem Description
You have a friend who is typing their name
into a keyboard. Sometimes when typing a character c
, the key might get long pressed, meaning the character gets typed 1 or more times instead of just once.
Given two strings:
name
: the intended name your friend wanted to typetyped
: the actual characters that were typed on the keyboard
You need to determine if typed
could have been produced by typing name
with some characters being long pressed.
Return True
if it's possible that typed
was your friend's attempt at typing name
(with potential long presses), and False
otherwise.
For example:
-
If
name = "alex"
andtyped = "aaleex"
, this returnsTrue
because:'a'
was typed once inname
but twice intyped
(long pressed)'l'
was typed once in both'e'
was typed once inname
but twice intyped
(long pressed)'x'
was typed once in both
-
If
name = "saeed"
andtyped = "ssaaedd"
, this returnsFalse
because:- Although some characters are long pressed correctly, the final
'd'
appears twice intyped
but only once inname
, and there's no second'e'
before it to match the pattern inname
- Although some characters are long pressed correctly, the final
The key insight is that every character in name
must appear in typed
in the same order, and each character group in typed
must have at least as many occurrences as the corresponding group in name
.
Intuition
To solve this problem, we need to think about what happens when someone types with potential long presses. The key observation is that the characters must appear in the exact same order in both strings, but in typed
, each character can appear more times than in name
due to long pressing.
Let's think about how we would manually check if typed
could be derived from name
:
- We'd go through both strings character by character
- For each character position in
name
, we'd check if it matches the current position intyped
- Since long pressing means repeating the same character, we'd count consecutive occurrences of each character in both strings
- The count in
typed
must be at least as much as inname
(equal or more due to long pressing)
This naturally leads us to a two-pointer approach where we process groups of identical consecutive characters. For instance, if name
has "aa" and typed
has "aaaa", that's valid because we typed 'a' 4 times instead of 2 (long pressed). But if name
has "aaa" and typed
has "aa", that's invalid because we can't have fewer occurrences.
The algorithm emerges from this insight:
- Use pointer
i
forname
and pointerj
fortyped
- At each step, if characters don't match, return
False
immediately - Count consecutive identical characters starting from current positions in both strings
- If
typed
has fewer consecutive characters thanname
for any character group, it's impossible to producetyped
fromname
- Move both pointers to the next different character and repeat
- Finally, ensure we've consumed both strings completely
This approach efficiently validates whether each character group in typed
could have been produced by typing the corresponding group in name
with potential long presses.
Learn more about Two Pointers patterns.
Solution Approach
We implement the solution using a two-pointer technique to traverse both strings simultaneously while comparing character groups.
Step-by-step implementation:
-
Initialize pointers and lengths:
- Set
i = 0
andj = 0
to point to the start ofname
andtyped
respectively - Store lengths
m = len(name)
andn = len(typed)
for boundary checking
- Set
-
Main traversal loop: While both pointers are within bounds (
i < m
andj < n
):a. Character matching check:
- If
name[i] != typed[j]
, the characters don't match, returnFalse
b. Count consecutive characters in
name
:- Initialize
x = i + 1
- While
x < m
andname[x] == name[i]
, incrementx
- This gives us
x - i
occurrences of the current character inname
c. Count consecutive characters in
typed
:- Initialize
y = j + 1
- While
y < n
andtyped[y] == typed[j]
, incrementy
- This gives us
y - j
occurrences of the current character intyped
d. Validate character group counts:
- If
x - i > y - j
, it meanstyped
has fewer occurrences thanname
- This is impossible with long pressing, so return
False
e. Move to next character groups:
- Update
i = x
andj = y
to point to the next different characters
- If
-
Final validation:
- After the loop, check if both strings have been completely traversed
- Return
i == m and j == n
- This ensures we've processed all characters in both strings
Example walkthrough:
For name = "alex"
and typed = "aaleex"
:
- Compare 'a' groups:
name
has 1,typed
has 2 β (long pressed) - Compare 'l' groups: both have 1 β
- Compare 'e' groups:
name
has 1,typed
has 2 β (long pressed) - Compare 'x' groups: both have 1 β
- Both strings fully traversed, return
True
The algorithm runs in O(m + n)
time complexity where m
and n
are the lengths of the strings, as we traverse each string once. Space complexity is O(1)
as we only use a constant amount of extra space.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the algorithm with name = "alex"
and typed = "aaleex"
:
Initial Setup:
i = 0
,j = 0
(pointers for name and typed)m = 4
,n = 6
(lengths of strings)
Iteration 1: Processing 'a' groups
- Current characters:
name[0] = 'a'
,typed[0] = 'a'
β (match) - Count 'a' in name: Starting from i=0, we find 1 consecutive 'a' (stops at index 1)
- Count 'a' in typed: Starting from j=0, we find 2 consecutive 'a's (stops at index 2)
- Compare counts: name has 1, typed has 2 β Valid (2 β₯ 1, could be long pressed)
- Update pointers:
i = 1
,j = 2
Iteration 2: Processing 'l' groups
- Current characters:
name[1] = 'l'
,typed[2] = 'l'
β (match) - Count 'l' in name: 1 consecutive 'l' (stops at index 2)
- Count 'l' in typed: 1 consecutive 'l' (stops at index 3)
- Compare counts: both have 1 β Valid (1 β₯ 1)
- Update pointers:
i = 2
,j = 3
Iteration 3: Processing 'e' groups
- Current characters:
name[2] = 'e'
,typed[3] = 'e'
β (match) - Count 'e' in name: 1 consecutive 'e' (stops at index 3)
- Count 'e' in typed: 2 consecutive 'e's (stops at index 5)
- Compare counts: name has 1, typed has 2 β Valid (2 β₯ 1, could be long pressed)
- Update pointers:
i = 3
,j = 5
Iteration 4: Processing 'x' groups
- Current characters:
name[3] = 'x'
,typed[5] = 'x'
β (match) - Count 'x' in name: 1 consecutive 'x' (reaches end at index 4)
- Count 'x' in typed: 1 consecutive 'x' (reaches end at index 6)
- Compare counts: both have 1 β Valid (1 β₯ 1)
- Update pointers:
i = 4
,j = 6
Final Check:
i = 4 = m
(processed all of name)j = 6 = n
(processed all of typed)- Both strings fully traversed β Return
True
The typed string "aaleex" could indeed be produced by typing "alex" with 'a' and 'e' being long pressed.
Solution Implementation
1class Solution:
2 def isLongPressedName(self, name: str, typed: str) -> bool:
3 """
4 Check if 'typed' could be a long-pressed version of 'name'.
5
6 Args:
7 name: The intended name string
8 typed: The actually typed string (possibly with long-pressed keys)
9
10 Returns:
11 True if typed could be produced by long-pressing name, False otherwise
12 """
13 name_length = len(name)
14 typed_length = len(typed)
15
16 # Initialize pointers for both strings
17 name_index = 0
18 typed_index = 0
19
20 # Process both strings simultaneously
21 while name_index < name_length and typed_index < typed_length:
22 # Characters must match at current positions
23 if name[name_index] != typed[typed_index]:
24 return False
25
26 # Count consecutive occurrences of current character in name
27 next_name_index = name_index + 1
28 while next_name_index < name_length and name[next_name_index] == name[name_index]:
29 next_name_index += 1
30
31 # Count consecutive occurrences of current character in typed
32 next_typed_index = typed_index + 1
33 while next_typed_index < typed_length and typed[next_typed_index] == typed[typed_index]:
34 next_typed_index += 1
35
36 # Calculate the count of current character in both strings
37 name_char_count = next_name_index - name_index
38 typed_char_count = next_typed_index - typed_index
39
40 # Typed must have at least as many occurrences as name (can have more due to long press)
41 if name_char_count > typed_char_count:
42 return False
43
44 # Move pointers to the next different character
45 name_index = next_name_index
46 typed_index = next_typed_index
47
48 # Both strings must be fully processed
49 return name_index == name_length and typed_index == typed_length
50
1class Solution {
2 /**
3 * Determines if typed string could be a result of long pressing keys while typing name.
4 * Each character in name must appear in typed with at least the same frequency in each group.
5 *
6 * @param name The intended name to type
7 * @param typed The actual typed string (possibly with long pressed keys)
8 * @return true if typed could be the result of long pressing while typing name, false otherwise
9 */
10 public boolean isLongPressedName(String name, String typed) {
11 int nameLength = name.length();
12 int typedLength = typed.length();
13 int nameIndex = 0;
14 int typedIndex = 0;
15
16 // Process both strings character by character
17 while (nameIndex < nameLength && typedIndex < typedLength) {
18 // Characters at current positions must match
19 if (name.charAt(nameIndex) != typed.charAt(typedIndex)) {
20 return false;
21 }
22
23 // Count consecutive occurrences of current character in name
24 int nameGroupEnd = nameIndex + 1;
25 while (nameGroupEnd < nameLength &&
26 name.charAt(nameGroupEnd) == name.charAt(nameIndex)) {
27 nameGroupEnd++;
28 }
29
30 // Count consecutive occurrences of current character in typed
31 int typedGroupEnd = typedIndex + 1;
32 while (typedGroupEnd < typedLength &&
33 typed.charAt(typedGroupEnd) == typed.charAt(typedIndex)) {
34 typedGroupEnd++;
35 }
36
37 // Calculate group sizes
38 int nameGroupSize = nameGroupEnd - nameIndex;
39 int typedGroupSize = typedGroupEnd - typedIndex;
40
41 // Typed must have at least as many characters in each group as name
42 if (nameGroupSize > typedGroupSize) {
43 return false;
44 }
45
46 // Move to next character groups
47 nameIndex = nameGroupEnd;
48 typedIndex = typedGroupEnd;
49 }
50
51 // Both strings must be fully processed
52 return nameIndex == nameLength && typedIndex == typedLength;
53 }
54}
55
1class Solution {
2public:
3 bool isLongPressedName(string name, string typed) {
4 int nameLength = name.length();
5 int typedLength = typed.length();
6 int nameIndex = 0;
7 int typedIndex = 0;
8
9 // Process both strings character by character
10 while (nameIndex < nameLength && typedIndex < typedLength) {
11 // If current characters don't match, it's not a valid long press
12 if (name[nameIndex] != typed[typedIndex]) {
13 return false;
14 }
15
16 // Count consecutive occurrences of current character in name
17 int nameCharCount = nameIndex + 1;
18 while (nameCharCount < nameLength && name[nameCharCount] == name[nameIndex]) {
19 ++nameCharCount;
20 }
21
22 // Count consecutive occurrences of current character in typed
23 int typedCharCount = typedIndex + 1;
24 while (typedCharCount < typedLength && typed[typedCharCount] == typed[typedIndex]) {
25 ++typedCharCount;
26 }
27
28 // Check if typed has at least as many occurrences as name
29 // (long press means same or more characters)
30 if (nameCharCount - nameIndex > typedCharCount - typedIndex) {
31 return false;
32 }
33
34 // Move to next group of characters
35 nameIndex = nameCharCount;
36 typedIndex = typedCharCount;
37 }
38
39 // Both strings should be fully processed for a valid match
40 return nameIndex == nameLength && typedIndex == typedLength;
41 }
42};
43
1/**
2 * Checks if the typed string could be a long-pressed version of the name string.
3 * In a long-pressed string, characters can be repeated multiple times due to holding the key.
4 * @param name - The original intended name
5 * @param typed - The actually typed string (potentially with long-pressed characters)
6 * @returns true if typed could be a long-pressed version of name, false otherwise
7 */
8function isLongPressedName(name: string, typed: string): boolean {
9 const nameLength: number = name.length;
10 const typedLength: number = typed.length;
11
12 let nameIndex: number = 0;
13 let typedIndex: number = 0;
14
15 // Process both strings character by character
16 while (nameIndex < nameLength && typedIndex < typedLength) {
17 // If current characters don't match, it's not a valid long-press
18 if (name[nameIndex] !== typed[typedIndex]) {
19 return false;
20 }
21
22 // Count consecutive occurrences of current character in name
23 let nextNameIndex: number = nameIndex + 1;
24 while (nextNameIndex < nameLength && name[nextNameIndex] === name[nameIndex]) {
25 nextNameIndex++;
26 }
27
28 // Count consecutive occurrences of current character in typed
29 let nextTypedIndex: number = typedIndex + 1;
30 while (nextTypedIndex < typedLength && typed[nextTypedIndex] === typed[typedIndex]) {
31 nextTypedIndex++;
32 }
33
34 // The typed string must have at least as many occurrences as the name
35 const nameCharCount: number = nextNameIndex - nameIndex;
36 const typedCharCount: number = nextTypedIndex - typedIndex;
37 if (nameCharCount > typedCharCount) {
38 return false;
39 }
40
41 // Move to the next group of characters
42 nameIndex = nextNameIndex;
43 typedIndex = nextTypedIndex;
44 }
45
46 // Both strings must be fully processed for a valid match
47 return nameIndex === nameLength && typedIndex === typedLength;
48}
49
Time and Space Complexity
Time Complexity: O(m + n)
, where m
is the length of the string name
and n
is the length of the string typed
.
The algorithm uses two pointers i
and j
to traverse through both strings. In each iteration of the main while loop:
- We find consecutive occurrences of the same character in
name
starting from positioni
(advancing pointerx
) - We find consecutive occurrences of the same character in
typed
starting from positionj
(advancing pointery
) - We then jump both pointers
i
andj
to positionsx
andy
respectively
Since each character in both strings is visited exactly once (either by the main pointers i
/j
or by the auxiliary pointers x
/y
), the total number of operations is proportional to m + n
.
Space Complexity: O(1)
The algorithm only uses a constant amount of extra space for the variables m
, n
, i
, j
, x
, and y
. No additional data structures are created that scale with the input size.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Not Handling Trailing Characters in typed
The Problem:
A common mistake is assuming that if we've processed all characters in name
, we're done. However, typed
might have extra characters at the end that don't correspond to any character in name
.
Example:
name = "alex"
typed = "aaleexy"
Here, after matching "alex" with "aleex", there's an extra 'y' in typed
. This should return False
, but if we only check name_index == name_length
without verifying that typed
is also fully consumed, we might incorrectly return True
.
Solution: Always verify both pointers have reached the end of their respective strings:
return name_index == name_length and typed_index == typed_length
Pitfall 2: Incorrect Character Group Comparison
The Problem: When comparing character groups, developers might accidentally compare individual characters instead of counting the entire group, leading to premature pointer advancement.
Incorrect approach:
# Wrong: This only compares one character at a time
while i < len(name) and j < len(typed):
if name[i] == typed[j]:
i += 1
j += 1
elif j > 0 and typed[j] == typed[j-1]:
j += 1 # Skip long-pressed character
else:
return False
Why it fails:
This approach doesn't properly handle cases where the same character appears in different positions in name
. For example:
name = "kikcxmvzi"
typed = "kiikcxxmmvvzzi"
The incorrect approach might match the first 'k' in name
with both 'k's in "kiik" of typed
, causing misalignment.
Solution: Count and compare entire character groups before moving pointers:
# Count all consecutive occurrences of current character in name next_name_index = name_index + 1 while next_name_index < name_length and name[next_name_index] == name[name_index]: next_name_index += 1 # Count all consecutive occurrences in typed next_typed_index = typed_index + 1 while next_typed_index < typed_length and typed[next_typed_index] == typed[typed_index]: next_typed_index += 1 # Compare group counts if (next_name_index - name_index) > (next_typed_index - typed_index): return False
Pitfall 3: Off-by-One Errors in Counting
The Problem: When counting consecutive characters, it's easy to make off-by-one errors by forgetting to include the current character in the count or by incorrectly initializing the counting pointer.
Incorrect:
# Wrong: Starting from current index instead of next
next_index = name_index # Should be name_index + 1
while next_index < len(name) and name[next_index] == name[name_index]:
next_index += 1
This would cause an infinite loop since name[name_index] == name[name_index]
is always true.
Solution: Always start counting from the next position:
next_index = name_index + 1 # Start from the next character
while next_index < len(name) and name[next_index] == name[name_index]:
next_index += 1
count = next_index - name_index # This gives the correct count
Which type of traversal does breadth first search do?
Recommended Readings
Tech Interview Pattern Two Pointers Introduction If you prefer videos here's a super quick introduction to Two Pointers div class responsive iframe iframe src https www youtube com embed xZ4AfXHQ1VQ title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture allowfullscreen iframe div Two pointers is a common interview
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Donβt Miss This!