LeetCode 844. 比较含退格的字符串 | Python

844. 比较含退格的字符串


题目来源:力扣(LeetCode)https://leetcode-cn.com/problems/backspace-string-compare/

题目


给定 ST 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果。 # 代表退格字符。

**注意:**如果对空文本输入退格字符,文本继续为空。

示例 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”。

提示:

  1. 1 <= S.length <= 200
  2. 1 <= T.length <= 200
  3. ST 只含有小写字母以及字符 '#'

进阶:

  • 你可以用 O(N) 的时间复杂度和 O(1) 的空间复杂度解决该问题吗?

解题思路


思路:栈、双指针

先看题目,题目给定两个字符串 ST,其中两个字符串中可能含有 # 字符,这里 # 字符,表示退格字符。

题目要求,若将 ST 分别输入文本编辑器,判断是否相等?

其中还有提示及需要注意的部分:

  • ST 只含有小写字母以及字符 '#'
  • 空文本输入 “#” 字符,文本最终还是为空。
  • ST 两者的长度都大于或等于 1,小于或等于 200。

这里看看题目示例 1 和示例 2:

示例 1

输入:S = "ab#c", T = "ad#c"
  • S 字符串中,字符 b 后面紧跟 # 字符,那么 b 字符将会被删除,所以这里最终输出的结果会是 ac;

  • T 字符串中,字符 d 后面跟 # 字符,那么 d 字符将会被删除,所以输出的结果也是 ac。

所以两者相同。

示例 2

输入:S = "ab##", T = "c#d#"

这里跟示例 1 不同的地方在于,这里存在两个 “#” 字符。这里也看看是如何变化的?

  • S 字符串中,字符 b 后面紧跟两个 # 字符。首先先明确在文本输入字符串时,是按照顺序输入的,那么字符 b 遇到第一个 # 时,先将字符 b 删除,剩下字符 a,再次遇到第二个 # 时,a 字符被删除,那么最终文本为空;

  • T 字符串中,这里比较好理解,就是输入 c 字符,然后被删除,接着输入字符 d,再次删除,最终文本也为空。

所以这两者都相同。

结合这两个示例看,不管 # 字符有多少,只要遇到 # 字符,(除空文本外)总有对应的字符需要被删除。那么我们可以使用栈来模拟这个过程,遍历字符串,判断其中的字符:

  • 如果字符为非 # 符号,那么将字符压入栈中;
  • 如果字符为 # 符号,那么将栈顶的字符弹出。

这里需要注意,本篇文章用 list 实现栈,这里 list 为空时需要注意弹出元素会抛出异常。

具体代码实现如下:

class Solution:
    def backspaceCompare(self, S: str, T: str) -> bool:
        def text_input(text):
            # 栈
            stack = []
            # 遍历字符串
            for ch in text:
                # 普通字符入栈
                if ch != "#":
                    stack.append(ch)
                # "#" 字符且栈非空时,弹出
                elif stack:
                    stack.pop()          
            
            return ''.join(stack)
        # 判断两者是否相同
        return text_input(S) == text_input(T)
复杂度分析
  • 时间复杂度: O ( n + m ) O(n+m) O(n+m) n n n m m m 分别表示 ST 两个字符串的长度。这里需要分别遍历两个字符串一次。
  • 空间复杂度: O ( n + m ) O(n+m) O(n+m)
双指针

根据前面对示例的分析,我们可以发现,# 字符只会影响其前面的普通字符,也就是说对于普通字符是否会被删除,取决于它后面的 # 字符。那么,我们可以考虑逆序遍历字符串,判断是否存在 # 字符,进而确定是否需要删除字符。

再看示例 2,

输入:S = "ab##", T = "c#d#"

这里 S 有两个连续 #,这里逆序遍历时,不能单纯的仅对前一位字符进行判断。在这里说下具体的做法:

  • 首先定义双指针,分别指向两个字符串的末尾,开始逆序遍历;
  • 定义变量 cnt,这里用来记录 # 出现的次数;
  • 当遇到 # 时,那么 cnt 要相应加 1;
  • 如果遇到的是普通字符,这里根据 cnt 来判断是否需要删除字符:
    • 当 cnt 为 0 时,表示当前普通字符后面没有 # 字符,此处不需要变动;
    • 若 cnt 不为 0,那么这里要该字符要删除,同时更新 cnt,让 cnt 减 1。
  • 遍历完字符串,或遍历找到的字符不同时终止,返回对应的结果。

在将前面的做法实现时,遍历字符串,根据 # 的数量 cnt 对字符串进行处理,会遇到这样的情况:

  • cnt 为 0,两指针都指向某个字符时,这里要先判断字符,若相同,继续判断;若不同,则直接返回 False;
  • 若其中仅有一个字符串已经遍历完成时,那么这里应该直接返回 False。因为另外一个字符串未遍历完成,一定是停在某个字符(假设为 a)等待判断,而字符串遍历完成,也就表示并未出现需要判断的字符,也就没有字符能与 a 比较判断,这里也就能直接给出两字符串不同的结论。
  • 两个字符串都遍历完成,返回 True。

具体的代码实现如下。

class Solution:
    def backspaceCompare(self, S: str, T: str) -> bool:
        # 定义指针,p 指向 S 末尾,q 指向 T 末尾
        p = len(S) - 1
        q = len(T) - 1

        # 定义变量 cnt_S,cnt_T,分别 '#' 的数量变化
        cnt_S = 0
        cnt_T = 0

        while p >= 0 or q >= 0:
            # 先遍历字符串 S
            while p >= 0:
                # 字符为 '#',cnt_S 加 1,同时 p 指针往左移动
                if S[p] == '#':
                    cnt_S += 1
                    p -= 1
                # 字符不为 '#',且 cnt_S 不为 0,当前字符要删除,更新 cnt_S,移动 p 指针
                elif cnt_S > 0:
                    cnt_S -= 1
                    p -= 1
                # 为普通字符,且 cnt_S 为 0,跳出循环,等待判断
                else:
                    break
            
            # 遍历字符串 T
            # 逻辑与上面相同
            while q >= 0:
                if T[q] == '#':
                    cnt_T += 1
                    q -= 1
                elif cnt_T > 0:
                    cnt_T -= 1
                    q -= 1
                else:
                    break

            # 此时判断两指针对应的字符
            # 字符串都未遍历完的情况
            if p >= 0 and q >= 0:
                # 对应字符不同,直接返回 False
                if S[p] != T[q]:
                    return False
            # 字符串只有一个遍历完的情况
            elif p >= 0 or q >= 0:
                return False

            # 上面情况不满足时,需要继续判断,继续移动 p, q 指针
            p -= 1
            q -= 1
        
        return True
复杂度分析
  • 时间复杂度: O ( n + m ) O(n+m) O(n+m) n n n m m m 分别表示 ST 两个字符串的长度。这里需要分别遍历两个字符串一次。
  • 空间复杂度: O ( 1 ) O(1) O(1)。仅使用了常数个变量。

欢迎关注


公众号 【书所集录

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值