比较含退格的字符串
力扣题目链接:https://leetcode-cn.com/problems/backspace-string-compare
给定 S 和 T 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果。# 代表退格字符。
注意:如果对空文本输入退格字符,文本继续为空。
示例 1:
- 输入:S = "ab#c", T = "ad#c"
- 输出:true
- 解释:S 和 T 都会变成 “ac”。
示例 2:
- 输入:S = "ab##", T = "c#d#"
- 输出:true
- 解释:S 和 T 都会变成 “”。
示例 3:
- 输入:S = "a##c", T = "#a#c"
- 输出:true
- 解释:S 和 T 都会变成 “c”。
示例 4:
- 输入:S = "a#c", T = "b"
- 输出:false
- 解释:S 会变成 “c”,但 T 仍然是 “b”。
思路
本文将给出 空间复杂度的栈模拟方法 以及空间复杂度是的双指针方法。
普通方法(使用栈的思路)
这道题目一看就是要使用栈的节奏,这种匹配(消除)问题也是栈的擅长所在,跟着一起刷题的同学应该知道,在栈与队列:匹配问题都是栈的强项,我就已经提过了一次使用栈来做类似的事情了。
那么本题,确实可以使用栈的思路,但是没有必要使用栈,因为最后比较的时候还要比较栈里的元素,有点麻烦。
这里直接使用字符串string,来作为栈,末尾添加和弹出,string都有相应的接口,最后比较的时候,只要比较两个字符串就可以了,比比较栈里的元素方便一些。
代码如下:
- class Solution {
- public:
- bool backspaceCompare(string S, string T) {
- string s; // 当栈来用
- string t; // 当栈来用
- for (int i = 0; i < S.size(); i++) {
- if (S[i] != '#') s += S[i];
- else if (!s.empty()) {
- s.pop_back();
- }
- for (int i = 0; i < T.size(); i++) {
- if (T[i] != '#') t += T[i];
- else if (!t.empty()) {
- t.pop_back();
- }
- }
- if (s == t) return true; // 直接比较两个字符串是否相等,比用栈来比较方便多了
- return false;
- }
- };
时间复杂度:,n为S的长度,m为T的长度 ,也可以理解是的时间复杂度
空间复杂度:当然以上代码,大家可以发现有重复的逻辑处理S,处理T,可以把这块公共逻辑抽离出来,代码精简如下:
- class Solution {
- private:
- string getString(const string& S) {
- string s;
- for (int i = 0; i < S.size(); i++) {
- if (S[i] != '#') s += S[i];
- else if (!s.empty()) {
- s.pop_back();
- }
- }
- return s;
- }
- public:
- bool backspaceCompare(string S, string T) {
- return getString(S) == getString(T);
- }
- };
性能依然是:
- 时间复杂度:
- 空间复杂度:
优化方法(从后向前双指针)
当然还可以有使用 的空间复杂度来解决该问题。
同时从后向前遍历S和T(i初始为S末尾,j初始为T末尾),记录#的数量,模拟消除的操作,如果#用完了,就开始比较S[i]和S[j]。
动画如下:
如果S[i]和S[j]不相同返回false,如果有一个指针(i或者j)先走到的字符串头部位置,也返回false。
代码如下:
- class Solution {
- public:
- bool backspaceCompare(string S, string T) {
- int sSkipNum = 0; // 记录S的#数量
- int tSkipNum = 0; // 记录T的#数量
- int i = S.size() - 1;
- int j = T.size() - 1;
- while (1) {
- while (i >= 0) { // 从后向前,消除S的#
- if (S[i] == '#') sSkipNum++;
- else {
- if (sSkipNum > 0) sSkipNum--;
- else break;
- }
- i--;
- }
- while (j >= 0) { // 从后向前,消除T的#
- if (T[j] == '#') tSkipNum++;
- else {
- if (tSkipNum > 0) tSkipNum--;
- else break;
- }
- j--;
- }
- // 后半部分#消除完了,接下来比较S[i] != T[j]
- if (i < 0 || j < 0) break; // S 或者T 遍历到头了
- if (S[i] != T[j]) return false;
- i--;j--;
- }
- // 说明S和T同时遍历完毕
- if (i == -1 && j == -1) return true;
- return false;
- }
- };
- 时间复杂度:
- 空间复杂度:
其他语言版本
Java:
- // 普通方法(使用栈的思路)
- class Solution {
- public boolean backspaceCompare(String s, String t) {
- StringBuilder ssb = new StringBuilder(); // 模拟栈
- StringBuilder tsb = new StringBuilder(); // 模拟栈
- // 分别处理两个 String
- for (char c : s.toCharArray()) {
- if (c != '#') {
- ssb.append(c); // 模拟入栈
- } else if (ssb.length() > 0){ // 栈非空才能弹栈
- ssb.deleteCharAt(ssb.length() - 1); // 模拟弹栈
- }
- }
- for (char c : t.toCharArray()) {
- if (c != '#') {
- tsb.append(c); // 模拟入栈
- } else if (tsb.length() > 0){ // 栈非空才能弹栈
- tsb.deleteCharAt(tsb.length() - 1); // 模拟弹栈
- }
- }
- return ssb.toString().equals(tsb.toString());
- }
- }
python
- class Solution:
- def get_string(self, s: str) -> str :
- bz = []
- for i in range(len(s)) :
- c = s[i]
- if c != '#' :
- bz.append(c) # 模拟入栈
- elif len(bz) > 0: # 栈非空才能弹栈
- bz.pop() # 模拟弹栈
- return str(bz)
- def backspaceCompare(self, s: str, t: str) -> bool:
- return self.get_string(s) == self.get_string(t)
- pass
Go
- func getString(s string) string {
- bz := []rune{}
- for _, c := range s {
- if c != '#' {
- bz = append(bz, c); // 模拟入栈
- } else if len(bz) > 0 { // 栈非空才能弹栈
- bz = bz[:len(bz)-1] // 模拟弹栈
- }
- }
- return string(bz)
- }
- func backspaceCompare(s string, t string) bool {
- return getString(s) == getString(t)
- }
JavaScript
- // 双栈
- var backspaceCompare = function(s, t) {
- const arrS = [], arrT = []; // 数组作为栈使用
- for(let char of s){
- char === '#' ? arrS.pop() : arrS.push(char);
- }
- for(let char of t){
- char === '#' ? arrT.pop() : arrT.push(char);
- }
- return arrS.join('') === arrT.join(''); // 比较两个字符串是否相等
- };
- //双栈精简
- var backspaceCompare = function(s, t) {
- const getString = s => {
- let arrS = [];
- for(let char of s){
- char === '#' ? arrS.pop() : arrS.push(char);
- }
- return arrS.join('');
- }
- return getString(s) === getString(t);
- };
- //双指针
- var backspaceCompare = function(s, t) {
- let sSkipNum = 0; // 记录s的#数量
- let tSkipNum = 0; // 记录t的#数量
- let i = s.length - 1, j = t.length - 1;
- while(true) {
- while(i >= 0){ // 从后向前,消除s的#
- if(s[i] === '#') sSkipNum++;
- else {
- if (sSkipNum > 0) sSkipNum--;
- else break;
- }
- i--;
- }
- while (j >= 0) { // 从后向前,消除t的#
- if (t[j] === '#') tSkipNum++;
- else {
- if (tSkipNum > 0) tSkipNum--;
- else break;
- }
- j--;
- }
- // 后半部分#消除完了,接下来比较s[i] != t[j]
- if (i < 0 || j < 0) break; // s 或者t 遍历到头了
- if (s[i] !== t[j]) return false;
- i--;j--;
- }
- // 说明s和t同时遍历完毕
- if (i == -1 && j == -1) return true;
- return false;
- };