leetcode844:比较含退格的字符串

题干

题目分析

两个字符串要进行比较,#代表着回车,也就是删除之前的字符。

若按照遍历的惯例,选择从前到后遍历,但这样没法判断,因为#之前被删除的部分是不需要相同的。

因此考虑到#的含义,我们应该选择从后往前遍历。

从后往前遍历,若当前下标所指向的字符不是#,需要判断这个数是否是被删除的数,如果不是被删除的数,才需要比较是否相等。

这就引出一个问题------------如何判断这个数是否被删除了?以及如何让两个字符串能够比对?

若直接按照下标从后向前遍历,但两个删除后的实际字符串,同一个字符的下标在两个原本的字符串中的下标可能是不相同的。

因此,我们要解决这些问题,我们要实现以下几点:

  • 首先要通过设定变量,记录#的数量。这一步的目的是跳过#前的字符,让下标指引到真正要比对的字符位置
  • 当前位置不是#的时候,我们要判断#的数量,如果不为0,则要跳过此字符,sum要减一
  • 满足时间复杂度O(n),空间复杂度O(1),不可以循环嵌套
  • 判断两个字符串比对时机的条件,当前字符sum为0且不为#的时候进行比对。为了方便比对,两个字符串的遍历要在同一个循环里面,这样才能确保每一轮比对都是对应的。

由此,我们开始进行代码的编写。

代码撰写与空间复杂度优化

常规的比较简单的方法,是使用StringBuffer或者StringBuilder,因为String是不可变的,而StringBuilder是可变的,因此使用StringBuilder可以直接删除不合适的字符,并返回最终字符串,将两个最终字符串进行比对。

代码如下:

java 复制代码
class Solution {
    public boolean backspaceCompare(String s, String t) {
        String s1 = fun(s);
        String s2 = fun(t);
        return s1.equals(s2);
    }


    private String fun(String s){
        int c = 0;
        StringBuilder ss = new StringBuilder();
        for (int i = s.length() - 1; i >= 0; i--){
            if (s.charAt(i) != '#'){
                if (c == 0){
                    ss.append(s.charAt(i));
                } else {
                    c--;
                }
            } else {
                c++;
            }
        }

        return ss.toString();
    }
}

但这个代码并不符合题目的要求,因为它使用了额外的空间存储两个字符串(创建了StringBuilder)

因此它的空间复杂度为O(m+n),不符合O(1)的要求。

为改进这个问题,按照之前分析的思路,我们使用字符串遍历,跳过#删除的字符的方法,一一进行比对

代码如下:

从后往前遍历的时候,我们考虑3中情况

  • 第一种:当前字符为#,记录#数量的sum++,指针前移
  • 第二种:当前字符不为#,但sum数不为0,证明这个位置的字符是要被跳过的,因此sum--,指针前移
  • 第三种:当前字符不为#,sum数为0,证明这个是删除后保留的字符,也就是要被进行比对的字符,此时通过break关键字退出循环,此刻slow指针所指向的下标便是本轮循环中要进行比对的下标。
java 复制代码
class Solution {
    public boolean backspaceCompare(String s, String t) {
        int slow1 = s.length() - 1; 
        int slow2 = t.length() - 1; 

        while (slow1 >= 0 || slow2 >= 0) {
  
            int backspaceCount1 = 0;
            while (slow1 >= 0) {
                if (s.charAt(slow1) == '#') {
                    backspaceCount1++; 
                    slow1--;
                } else if (backspaceCount1 > 0) {
                    backspaceCount1--; 
                    slow1--;
                } else {
                    break; 
                }
            }


            int backspaceCount2 = 0;
            while (slow2 >= 0) {
                if (t.charAt(slow2) == '#') {
                    backspaceCount2++; 
                    slow2--;
                } else if (backspaceCount2 > 0) {
                    backspaceCount2--; 
                    slow2--;
                } else {
                    break; 
                }
            }

  
            if (slow1 >= 0 && slow2 >= 0) {
                if (s.charAt(slow1) != t.charAt(slow2)) {
                    return false; 
                }
            } else if (slow1 >= 0 || slow2 >= 0) {
                return false; 
            }

            slow1--;
            slow2--;
        }

        return true;
    }
}

(这里可以用其他名字,比如tj代替slow1slow2,我这样写是因为写快慢指针的时候写习惯了所以用slow代指用来赋值的指针。)

思路易错点

被删除的字符要一个一个跳过

java 复制代码
else if (backspaceCount1 > 0) {
                    backspaceCount1--; 
                    slow1--;
                } 

我们分析这段代码,会发现遇到不是#,且sum不为0的字符时,我们跳过当前字符,sum--。

在初次分析的时候,我选择了slow=slow-sum;sum=0;来进行跳过多个字符。

但这样是错误的,以为批量跳过的时候,有可能跳过#,这样会导致程序逻辑上的错误。

因此我们要一一比对,精准记录每一个#字符

比对时,条件判断要精准

java 复制代码
            if (slow1 >= 0 && slow2 >= 0) {
                if (s.charAt(slow1) != t.charAt(slow2)) {
                    return false; 
                }
            } else if (slow1 >= 0 || slow2 >= 0) {
                return false; 
            }

如果直接使用s.charAt(slow1)!=t.charAt(slow2)进行判断,有可能会出现数组越界的错误。

因此在判断之前,我们首先要确保索引下标是可用的,因此首先要进行slow1>=0&&slow2>=0的判断。

相关推荐
狐狐生风几秒前
Python UV 完整安装教程
开发语言·python·uv
Kiyra4 分钟前
限流不是加个计数器就行:用 Lua 脚本实现多维度原子限流
开发语言·人工智能·网络协议·职场和发展·架构·lua·ai-native
雨落在了我的手上6 分钟前
初识java(二):数据类型与变量
java·开发语言
小闫BI设源码6 分钟前
当20个节点选出两个Master时:Elasticsearch的致命故障与解决方案
java·elasticsearch·jenkins·php·面试宝典·深入解析
洛水水14 分钟前
【力扣100题】22. 矩阵置零
算法·leetcode·矩阵
Liangwei Lin15 分钟前
LeetCode 78. 子集
数据结构·算法·leetcode
SamDeepThinking15 分钟前
千万级用户购物车系统的架构设计
java·后端·架构
liwulin050616 分钟前
【JAVAFX】从ORACLE JDK切换到国内的JDK以便使用JAVAFX功能
java·数据库·oracle
xcjbqd017 分钟前
提升Python编程效率的五大特性
开发语言·python
平凡但不平庸的码农23 分钟前
Go GMP 调度模型详解
开发语言·后端·golang