Files
leetcode-master/problems/0844.比较含退格的字符串.md
2021-08-24 13:11:57 +08:00

6.7 KiB
Raw Blame History

欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

844.比较含退格的字符串

力扣题目链接

给定 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”。

思路

本文将给出 空间复杂度O(n)的栈模拟方法 以及空间复杂度是O(1)的双指针方法。

普通方法(使用栈的思路)

这道题目一看就是要使用栈的节奏,这种匹配(消除)问题也是栈的擅长所在,跟着一起刷题的同学应该知道,在栈与队列:匹配问题都是栈的强项,我就已经提过了一次使用栈来做类似的事情了。

那么本题,确实可以使用栈的思路,但是没有必要使用栈,因为最后比较的时候还要比较栈里的元素,有点麻烦

这里直接使用字符串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;
    }
};
  • 时间复杂度:O(n + m) n为S的长度m为T的长度 也可以理解是O(n)的时间复杂度
  • 空间复杂度:O(n + m)

当然以上代码大家可以发现有重复的逻辑处理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);
    }
};

性能依然是:

  • 时间复杂度:O(n + m)
  • 空间复杂度:O(n + m)

优化方法(从后向前双指针)

当然还可以有使用 O(1) 的空间复杂度来解决该问题。

同时从后向前遍历S和Ti初始为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;
    }
};
  • 时间复杂度O(n + m)
  • 空间复杂度O(1)

其他语言版本

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

Go

JavaScript