【Leetcode每日一题】844. 比较含退格的字符串|重构字符串/双指针

在这里插入图片描述

前言:

昨天的【Leetcode每日一题】27. 原地移除元素|神级理解双指针一文中,生动形象的为大家讲解如何理解双指针,受到了很好的反馈,今天趁热打铁,瑶瑶子为大家带来一道双指针的plus版本题目,会比昨天的难一点,但是本质和逻辑是一样的(就是两个人干活,男女搭配,干活不累!)
在讲今天这道题目之前,推荐大家去做一下力扣283题目,这里给出链接和我的题解,和昨天27题非常类似,只有细小差别。
283. 移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。

class Solution1 {
    
    
    public void moveZeroes(int[] nums) {
    
    
        int quickIndex = 0;//快指针,用于遍历
        int slowIndex = 0;//慢指针用于挖坑
        for (; quickIndex < nums.length; quickIndex++) {
    
    
            if (nums[quickIndex] == 0) {
    
    
                continue;//遇见0就跳过
            }
            nums[slowIndex++] = nums[quickIndex];//慢指针在挖坑,等待快指针给过来的"萝卜"
        }
        for (; slowIndex < nums.length; slowIndex++)//慢指针把0填上去
        {
    
    
            nums[slowIndex] = 0;
        }
    }
}

题目描述

链接:844. 比较含退格的字符串

给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。
注意:如果对空文本输入退格字符,文本继续为空。

可以用 O(n) 的时间复杂度和 O(1) 的空间复杂度解决该问题吗?
(O(1)的复杂度会用方法2实现)

题目分析

方法1:

最容易想到的方法,也就是为两个字符串分别重写构造各自的新字符串,来存储删除后的两个新字符串。再把两个新字符串进行比较(非原地修改)

  • 设计一个方法,用于获取修改后的新字符串
  • 将两者对应删除空格后的新字符串进行比较

本质还是昨天所说的双指针,一个遍历,一个指向待插入位置(但是其实双指针我觉得,在这题当中,不是形式上的双指针,而是思想上的,需要体会,逻辑是完全一样

class Solution {
    
    
    public boolean backspaceCompare(String s, String t) {
    
    
        return newString(s).equals(newString(t));
    }
    //通过这个函数,得到退格后的新字符串(不含#的字符串)
    public String newString(String str) {
    
    
        StringBuffer ans = new StringBuffer();
        for (int i = 0; i < str.length(); i++) {
    
    
            if (str.charAt(i) != '#') {
    
    
                ans.append(str.charAt(i));//填入
            } else {
    
    
                if (ans.length() > 0) {
    
    
                    ans.deleteCharAt(ans.length() - 1);//慢指针遇到#,就把萝卜拔掉,不前行
                }
            }
        }
        return ans.toString();//将StringBuffer类型转换为String类型返回
    }
}

本质是快慢指针法,在newString这个方法中对一个字符串的操作中体现体现

  • 时间复杂度O(N+M)
  • 空间复杂度O(N+M)

方法2

也是双指针,与方法1以及之前所讲的双指针不同的是:快慢两个指针作用在同一个字符串/数组上;而纯双指针,即两个指针分工明确,各不相同,作用在不同的字符串上/数组。

具体用代码来体现(瑶瑶子附有有保姆级详细注释)

class Solution {
    
    
    public boolean backspaceCompare(String s, String t) {
    
    
        int pointerS = s.length() - 1;//指针1号指向s字符串中的待比较元素
        int pointerT = t.length() - 1;//指针2号指向t字符串中的待比较元素
        while (pointerS >= 0 || pointerT >= 0) {
    
    //注意这里是||,为什么不是&&?举例:hhh 和 空,结果还是false
            //求出s字符串中第一个待比较元素
            int skipS = 0;
            int slipT = 0;
            while (pointerS >= 0) {
    
    
                if (s.charAt(pointerS) == '#') {
    
    
                    skipS++;
                    pointerS--;//向后遍历下一个元素
                } else if (skipS > 0) {
    
    //类似于“出栈”过程,出栈之前必须判断栈是否为空!
                    pointerS--;
                    skipS--;
                } else {
    
    //即skipS=0,元素不为'#'的情况-->找到待比较元素
                    break;//跳出循环
                }
            }
            //同样的方法,找到t字符串中待比较元素
            while (pointerT >= 0) {
    
    
                if (t.charAt(pointerT) == '#') {
    
    
                    slipT++;
                    pointerT--;
                } else if (slipT > 0) {
    
    
                    pointerT--;
                    slipT--;
                } else {
    
    
                    break;
                }
            }
            //比较两个循环中分别出来的字符
            if (pointerS >= 0 && pointerT >= 0) {
    
    
                if (s.charAt(pointerS) != t.charAt(pointerT)) {
    
    
                    return false;
                }
            } else {
    
    
                if (pointerS >= 0 || pointerT >= 0)//一个字符串还存在字符待比较,另一个一个字符串的字符已经比较完:如:a null
                    return false;
            }

            //指针后退,为下一次比较做准备
            pointerS--;
            pointerT--;
        }
        //大循环跳出,说明两者皆为空字符串,返回true
        return true;
    }
}

易错点

  • 1:超出时间限制:每次循环比较字符后,没有让指针后退pointerS--;pointerT--
  • 2:指针越界异常(java.lang.StringIndexOutOfBoundsException: String index out of range: -1):在循环内,并不能保证pointerS和ponterT大于0,所以在进行charAt(pointerS)/charAt(pointerT)运算时,必须保证此时下标大于or等于0(if (pointerS >= 0 && pointerT >= 0))

方法2反思:
 双指针思想主要体现在pointerS和pointerB经过一些巧妙的处理while循环,指向各自字符串的待比较元素,并分别比较。
【重点】除了双指针思想;此题方法2:不得不学习的重点:
1. 对于删除空格,采用从后往前遍历方式
2. 巧妙利用计数器(skipS&skipT),记录指针所需要跳过的字符个数



write in the end:
后续还会更新很多双指针题目来加深对双指针的理解!以及持续更新Java刷题系列文章。还不快快关注![笔芯]

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Yaoyao2024/article/details/128794012