【leetcode】删除字符串中的所有相邻重复项II (双指针, 细节)

给你一个字符串 s,「k 倍重复项删除操作」将会从 s 中选择 k 个相邻且相等的字母,并删除它们,使被删去的字符串的左侧和右侧连在一起。

你需要对 s 重复进行无限次这样的删除操作,直到无法继续为止。

在执行完所有删除操作后,返回最终得到的字符串。

本题答案保证唯一。

示例 1:

输入:s = “abcd”, k = 2
输出:“abcd”
解释:没有要删除的内容。
示例 2:

输入:s = “deeedbbcccbdaa”, k = 3
输出:“aa”
解释:
先删除 “eee” 和 “ccc”,得到 “ddbbbdaa”
再删除 “bbb”,得到 “dddaa”
最后删除 “ddd”,得到 “aa”
示例 3:

输入:s = “pbbcggttciiippooaais”, k = 2
输出:“ps”

提示:

1 <= s.length <= 10^5
2 <= k <= 10^4
s 中只含有小写英文字母。

链接:https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string-ii

思路分析:

这道题就是重复进行删除操作直到无法完成。删除操作就是将连续k个相同字母从字符串中删掉。根据数据来判断时间复杂度只能在O(n)或者O(nlgn). 因此对于每一轮的删除操作必须用O(n)来解决。
我是采用的双指针中的”前后指针“思路。新建一个tmp字符串, l 留在原地,r先探测后面的元素,如果探测到 s[l] 重复了k次,就跳过,否则就加进tmp字符串里。这样就可以实现O(n)的删除操作了。
不过这里面涉及到许多的细节问题,当时竞赛为了求快,写了很多bug,结果错漏百出,反而耽搁了更多的时间。调试了40分钟的bug,中途还重构了一遍,才完成这道题。
之后我反思了一下,我觉得我的问题出现的原因是我只按照我大概的思路写代码,想到哪写到哪,在写的过程中没有具体分析。特别是写的过程中自己对变量的定位不清晰导致一连串的难以debug的错误。

因此,我决定细致的分析此类细节题,并且以后引以为戒。
先上代码,然后讲解。

class Solution {
public:
    string removeDuplicates(string s, int k) {
        if(s.length() == 0) return "";
        while(1)
        {
            int l = 0, r = 1, ok = 0;	//细节0
            string tmp;
            while(l < s.length())	//细节1
            {
                
                int cnt = 1;
                while(r < s.length() && s[r] == s[l] && cnt < k)	//细节2
                {
                    cnt++;
                    r++;
                }
                if(cnt < k)	//细节3
                {
                    while(cnt--) tmp.push_back(s[l++]);
                }
                else ok = 1;
                l = r;	//细节4
                r++;	
            }
            s = tmp;
            if(!ok) break;
        }
        return s;
    }
};

首先,我知道这道题使用双指针。那么我需要分析:l, r代表的是什么?
l 用来表示当前元素,r 用来探测当前元素( s[l] )是否重复k次,并最后为 l 指向新的位置。
所以,我们是要靠 l 遍历s字符串,r 作为探测。因此对于r来说要保证r = l+1,在 l 的后一位。细节1的条件就是 l < s.length().
在细节2中,r 向前探测的终止条件有两个:

  1. 重复次数达到 k 次。
  2. 重复次数没达到k次,中途就发现元素不相等。
    经过细节2的循环后,r 的位置是重复元素的后一个位置。比如说”eeed“,k = 2. 经过循环后 r 指向的是s[2],这个位置是 l 的下一个目标位置。因此有细节4的 l = r.
    不过这里有一个问题:当cnt < k 时,r 不会回头(其实你也可以让 r 回头). 因此在细节3中我们需要让这些不满足k次的重复元素都加进tmp里,即 l 前进cnt次或者 l 前进到 r 当前位置。
    最后,每次遍历前初始化ok=0,如果遍历中途发生过一次删除操作,即cnt == k,令ok = 1表示进行过该操作。如果遍历完ok一直为0,表示没进行过删除操作,退出循环。
    总之,写代码的过程需要非常清晰的知道每个变量的定位,这样才能又快又准!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值