LeetCode 925: Long Pressed Name (Two-Pointer Character Group Matching)
LeetCode 925StringTwo PointersToday we solve LeetCode 925 - Long Pressed Name.
Source: https://leetcode.com/problems/long-pressed-name/
English
Problem Summary
Given strings name and typed, determine whether typed can be produced by long-pressing some keys while typing name. Long-press means a character may appear more times than intended, but order cannot change.
Key Insight
Compare character groups from left to right. For each group in name, typed must have the same character and at least the same count. If typed has fewer occurrences in any group, it's invalid.
Brute Force and Limitations
Generating all long-press possibilities is exponential and unnecessary. Direct two-pointer group counting gives deterministic linear behavior.
Optimal Algorithm Steps
1) Use pointers i for name, j for typed.
2) While both are in range, characters must match at name[i] == typed[j].
3) Count consecutive identical chars in both strings: countName, countTyped.
4) If countTyped < countName, return false.
5) Continue until one string ends; valid only if both end together.
Complexity Analysis
Time: O(n + m), where n = name.length, m = typed.length.
Space: O(1).
Common Pitfalls
- Only checking character equality, but not group counts.
- Accepting leftover characters in typed after name is fully consumed.
- Forgetting edge cases like first character mismatch.
Reference Implementations (Java / Go / C++ / Python / JavaScript)
class Solution {
public boolean isLongPressedName(String name, String typed) {
int i = 0, j = 0;
int n = name.length(), m = typed.length();
while (i < n && j < m) {
if (name.charAt(i) != typed.charAt(j)) {
return false;
}
char c = name.charAt(i);
int cntName = 0;
while (i < n && name.charAt(i) == c) {
i++;
cntName++;
}
int cntTyped = 0;
while (j < m && typed.charAt(j) == c) {
j++;
cntTyped++;
}
if (cntTyped < cntName) {
return false;
}
}
return i == n && j == m;
}
}func isLongPressedName(name string, typed string) bool {
i, j := 0, 0
n, m := len(name), len(typed)
for i < n && j < m {
if name[i] != typed[j] {
return false
}
c := name[i]
cntName := 0
for i < n && name[i] == c {
i++
cntName++
}
cntTyped := 0
for j < m && typed[j] == c {
j++
cntTyped++
}
if cntTyped < cntName {
return false
}
}
return i == n && j == m
}class Solution {
public:
bool isLongPressedName(string name, string typed) {
int i = 0, j = 0;
int n = (int)name.size(), m = (int)typed.size();
while (i < n && j < m) {
if (name[i] != typed[j]) return false;
char c = name[i];
int cntName = 0;
while (i < n && name[i] == c) {
i++;
cntName++;
}
int cntTyped = 0;
while (j < m && typed[j] == c) {
j++;
cntTyped++;
}
if (cntTyped < cntName) return false;
}
return i == n && j == m;
}
};class Solution:
def isLongPressedName(self, name: str, typed: str) -> bool:
i = j = 0
n, m = len(name), len(typed)
while i < n and j < m:
if name[i] != typed[j]:
return False
c = name[i]
cnt_name = 0
while i < n and name[i] == c:
i += 1
cnt_name += 1
cnt_typed = 0
while j < m and typed[j] == c:
j += 1
cnt_typed += 1
if cnt_typed < cnt_name:
return False
return i == n and j == mvar isLongPressedName = function(name, typed) {
let i = 0, j = 0;
const n = name.length, m = typed.length;
while (i < n && j < m) {
if (name[i] !== typed[j]) return false;
const c = name[i];
let cntName = 0;
while (i < n && name[i] === c) {
i++;
cntName++;
}
let cntTyped = 0;
while (j < m && typed[j] === c) {
j++;
cntTyped++;
}
if (cntTyped < cntName) return false;
}
return i === n && j === m;
};中文
题目概述
给定 name 和 typed,判断 typed 是否可能由输入 name 时发生长按得到。长按只会让同一字符重复更多次,字符顺序不能变化。
核心思路
按“字符分组”进行双指针匹配。name 中每组字符在 typed 中必须是同一个字符,且出现次数不少于 name 对应组。
暴力解法与不足
暴力生成所有可能长按结果会指数爆炸。更好的方式是线性扫描两串并统计分组长度。
最优算法步骤
1)双指针 i、j 分别遍历 name 与 typed。
2)当前字符必须相等,否则直接 false。
3)分别统计当前字符在两串中的连续次数。
4)若 typed 次数小于 name 次数,false。
5)循环结束后,只有两串都恰好走到末尾才是 true。
复杂度分析
时间复杂度:O(n + m)。
空间复杂度:O(1)。
常见陷阱
- 只比较字符,不比较分组次数。
- name 结束后还放过 typed 的多余字符。
- 忽略首字符不匹配这类直接失败场景。
多语言参考实现(Java / Go / C++ / Python / JavaScript)
class Solution {
public boolean isLongPressedName(String name, String typed) {
int i = 0, j = 0;
int n = name.length(), m = typed.length();
while (i < n && j < m) {
if (name.charAt(i) != typed.charAt(j)) {
return false;
}
char c = name.charAt(i);
int cntName = 0;
while (i < n && name.charAt(i) == c) {
i++;
cntName++;
}
int cntTyped = 0;
while (j < m && typed.charAt(j) == c) {
j++;
cntTyped++;
}
if (cntTyped < cntName) {
return false;
}
}
return i == n && j == m;
}
}func isLongPressedName(name string, typed string) bool {
i, j := 0, 0
n, m := len(name), len(typed)
for i < n && j < m {
if name[i] != typed[j] {
return false
}
c := name[i]
cntName := 0
for i < n && name[i] == c {
i++
cntName++
}
cntTyped := 0
for j < m && typed[j] == c {
j++
cntTyped++
}
if cntTyped < cntName {
return false
}
}
return i == n && j == m
}class Solution {
public:
bool isLongPressedName(string name, string typed) {
int i = 0, j = 0;
int n = (int)name.size(), m = (int)typed.size();
while (i < n && j < m) {
if (name[i] != typed[j]) return false;
char c = name[i];
int cntName = 0;
while (i < n && name[i] == c) {
i++;
cntName++;
}
int cntTyped = 0;
while (j < m && typed[j] == c) {
j++;
cntTyped++;
}
if (cntTyped < cntName) return false;
}
return i == n && j == m;
}
};class Solution:
def isLongPressedName(self, name: str, typed: str) -> bool:
i = j = 0
n, m = len(name), len(typed)
while i < n and j < m:
if name[i] != typed[j]:
return False
c = name[i]
cnt_name = 0
while i < n and name[i] == c:
i += 1
cnt_name += 1
cnt_typed = 0
while j < m and typed[j] == c:
j += 1
cnt_typed += 1
if cnt_typed < cnt_name:
return False
return i == n and j == mvar isLongPressedName = function(name, typed) {
let i = 0, j = 0;
const n = name.length, m = typed.length;
while (i < n && j < m) {
if (name[i] !== typed[j]) return false;
const c = name[i];
let cntName = 0;
while (i < n && name[i] === c) {
i++;
cntName++;
}
let cntTyped = 0;
while (j < m && typed[j] === c) {
j++;
cntTyped++;
}
if (cntTyped < cntName) return false;
}
return i === n && j === m;
};
Comments