LeetCode 844. 比较含退格的字符串
题目描述


题意分析
将两个字符串分别输入空文本,其中
#删除此前仍然保留的最后一个字符;空文本上的退格无效。比较的是全部输入完成后的文本,原字符串长度可以不同,最终结果也可能为空。
解法:双指针从后往前跳过退格
核心思路
[!blue]
正序读取时,一个字母是否保留还取决于后面的退格。反过来从右向左读,就能先遇到会影响它的全部退格,因此不必像栈模拟那样构造最终文本。
两个字符串各维护一个指针和退格计数
skip。遇到#,表示还要跳过左侧一个普通字符,令skip加一;遇到普通字符且skip > 0,就跳过它并把计数减一;普通字符遇到skip == 0时,它不会再被右侧退格删除,就是最终文本从右向左的下一个字符。分别找到两个下一个有效字符后再比较:字符不同就失败,只有一侧还有有效字符也失败;相同则两边指针都左移,继续比较剩余部分。每个有效字符都按最终顺序配对,全部配对结束就说明两串相等。
字符耗尽后,剩余退格只相当于在空文本上删除,可以忽略。代码用值为 0 的字符表示「已经没有有效字符」;题目只含小写字母和
#,因此这个标记不会与输入字母混淆。
解题步骤
- 两个指针分别从字符串末尾开始。
- 只要任一原串还有未处理位置,就分别向左跳过退格和被删字符,停在下一个有效字符或字符串之外。
- 比较两侧有效字符,耗尽的一侧用 0 表示,不同时返回
false。- 相同时让两个指针各左移一次,继续下一轮;遍历结束后返回
true。
代码实现
class Solution {
public boolean backspaceCompare(String s, String t) {
int i = s.length() - 1;
int j = t.length() - 1;
int skipS = 0;
int skipT = 0;
while (i >= 0 || j >= 0) {
// 倒序先累计退格,再跳过对应数量的普通字符,停在下一有效字符。
while (i >= 0) {
char c = s.charAt(i);
if (c == '#') {
skipS++;
i--;
} else if (skipS > 0) {
skipS--;
i--;
} else {
break;
}
}
while (j >= 0) {
char c = t.charAt(j);
if (c == '#') {
skipT++;
j--;
} else if (skipT > 0) {
skipT--;
j--;
} else {
break;
}
}
char a = i >= 0 ? s.charAt(i) : 0;
char b = j >= 0 ? t.charAt(j) : 0;
if (a != b) {
return false;
}
i--;
j--;
}
return true;
}
}
func backspaceCompare(s string, t string) bool {
i, j := len(s)-1, len(t)-1
skipS, skipT := 0, 0
for i >= 0 || j >= 0 {
// 倒序先累计退格,再跳过对应数量的普通字符,停在下一有效字符。
for i >= 0 {
if s[i] == '#' {
skipS++
i--
} else if skipS > 0 {
skipS--
i--
} else {
break
}
}
for j >= 0 {
if t[j] == '#' {
skipT++
j--
} else if skipT > 0 {
skipT--
j--
} else {
break
}
}
var a byte = 0
var b byte = 0
if i >= 0 {
a = s[i]
}
if j >= 0 {
b = t[j]
}
if a != b {
return false
}
i--
j--
}
return true
}
复杂度分析
- 时间复杂度:$O(n+m)$,每个指针只向左移动。
- 空间复杂度:$O(1)$,只保存指针与退格计数。
关键点总结
[!green]
- 先识别井号,再判断普通字符是否需要删除。
- 两串使用各自的退格计数,独立寻找有效字符。
- 比较最终字符顺序,不比较原字符串长度。
- 每个指针只向左移动,满足线性时间、常数额外空间的进阶要求。
易错点总结
[!yellow]
- 用一个布尔值记录退格:不能表达连续多个删除。
- 只要一串耗尽就返回 true:另一串可能还剩未配对的有效字符,必须继续处理。
- 下标已经为负仍读取字符:退格可能把全部内容删除。
- 将退格理解为删除右侧字符:与实际输入顺序相反。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 2390. 从字符串中移除星号 | 中等 | 退格语义相同,原题返回删除后的文本,本题比较两串结果,还可从右向左跳过被删除字符。 |
| 1047. 删除字符串中的所有相邻重复项 | 简单 | 同样使用栈消除前缀末尾内容,原题由相邻相同字符触发,本题由退格符触发。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!