思路
有两个思路。
第一个思路是最容易想到的,用栈来保存字符,遇到’#‘则弹出一个元素即可,唯一要注意的是遇到’#'弹出时检查一下栈是否为空。不过这种做法是需要额外空间的。
第二个思路是重构字符串,把被回退的字符忽略掉。
由于’#‘本身就是在比较时要忽略的,因此把被回退的字符改为’#'更方便比较。
使用两个指针分别遍历两个重构后的字符串,若遇到’#‘则忽略,然后比较字符。要注意在忽略’#‘时可能会越界,因此每次检查’#'并递增后需要判断一下。
在思路一中用栈处理时,若两个栈长度不等则一定字符串不相等,但在思路二中可能存在字符串不等长但却相等的情况。因此在比较的时候要注意停止比较的条件。
我用第一个字符串s的遍历结束作为停止比较的条件。此时有三种情况:
- 第二个字符串t也遍历结束,这说明s和t是相等的
- t剩下没遍历的字符都是’#',此时s和t也是相等的
- t还有非‘#’字符没有遍历到,这说明s和t不相等
思路一代码
class Solution {
public:
bool backspaceCompare(string s, string t) {
stack<char> stack1; stack<char> stack2;
int sLength = s.length(), tLength = t.length();
int i = 0;
// 入栈
while (i < sLength) {
if (s[i] != '#')
stack1.push(s[i]);
else if (!stack1.empty())
stack1.pop();
i++;
}
// 相同方法处理t
i = 0;
while (i < tLength) {
if (t[i] != '#')
stack2.push(t[i]);
else if (!stack2.empty())
stack2.pop();
i++;
}
// 比较
if (stack1.size() != stack2.size())
return false;
i = 0;
while (!stack1.empty()) {
if (stack1.top() != stack2.top())
return false;
stack1.pop(); stack2.pop();
}
return true;
}
};
思路二代码
class Solution {
private:
void backspace(string& s) {
// 遍历s和t,将每个#前的第一个字母改为'#'
int i = 0;
while (i < s.length()) {
// 找到'#'
if (s[i] != '#') {
i++;
continue;
}
// 找到'#'前的第一个字母
int j = i++;
while ( j >= 0 && s[j] == '#') {
j--;
}
if (j < 0)
continue;
// 将其改为'#'
s[j] = '#';
}
}
public:
bool backspaceCompare(string s, string t) {
backspace(s); backspace(t);
int sLength = s.length(), tLength = t.length();
// 比较
int i = 0, j = 0;
while (i < sLength) {
// 忽略'#'
while (s[i] == '#') {
i++;
// s遍历完了
if (i == sLength)
// 若t也结束了或只剩下'#',则相同,否则不同
break;
}
// 此时s要么结束了,要么停在了不是#的地方
if (j == tLength)
// 若s结束了,则相同,否则不同
return i == sLength;
while (t[j] == '#') {
j++;
// 和上面同理
if (j == tLength) {
return i == sLength;
}
}
// 比较
if (s[i++] != t[j++])
return false;
}
// 此时s遍历完了,若t也遍历完则相同
if (j == tLength)
return true;
// 忽略剩下的'#'
while (t[j] == '#') {
j++;
if (j == tLength)
return true;
}
// 此时t还有剩下的但s已经完了
return false;
}
};