LeetCode 1209. 删除字符串中的所有相邻重复项 II

1209. 删除字符串中的所有相邻重复项 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 中只含有小写英文字母。

提示 1

Use a stack to store the characters, when there are k same characters, delete them.


提示 2

To make it more efficient, use a pair to store the value and the count of each character.

解法1:记忆计数

如果为每个字符设置计数器,就不必每次删除完字符后从头开始。这种方法具有线性复杂度,但需要额外空间存储字符的计数器。

1.初始长度为 n 的数组 counts。

2.遍历字符串:

  • 如果当前字符与上一个字符相等,令 counts[i] = counts[i - 1] + 1。
  • 否则,令 counts[i] = 1。
  • 如果 counts[i] = k,删除这 k 个字符,令 i = i - k。

Java版:

class Solution {
    public String removeDuplicates(String s, int k) {
        StringBuilder st = new StringBuilder(s);
        int[] counts = new int[st.length()];
        for (int i = 0; i < st.length(); i++) {
            if (i == 0 || st.charAt(i) != st.charAt(i - 1)) {
                counts[i] = 1;
            } else {
                counts[i] = counts[i - 1] + 1;
                if (counts[i] == k) {
                    st.delete(i - k + 1, i + 1);
                    i = i - k;
                }
            }
        }
        return st.toString();
    }
}

 Python3版:

class Solution:
    def removeDuplicates(self, s: str, k: int) -> str:
        counts = [0] * len(s)
        i = 0
        while i < len(s):
            if i == 0 or s[i] != s[i - 1]:
                counts[i] = 1
            else:
                counts[i] = counts[i - 1] + 1
                if counts[i] == k:
                    # [0, i - k]  [i - k + 1, i] [i + 1, n - 1]
                    s = s[:i - k + 1] + s[i + 1:]
                    i = i - k
            i += 1
        return s

复杂度分析

  • 时间复杂度:O(n),其中 n 是字符串长度。每个字符仅被处理一次。

  • 空间复杂度:O(n),存储每个字符的计数器。

解法2:栈

当前字符与前一个不同时,往栈中压入 1。否则栈顶元素加 1。

  • 迭代字符串:
  • 如果当前字符与前一个相同,栈顶元素加 1;否则,往栈中压入 1。
  • 如果栈顶元素等于 k,则从字符串中删除这 k 个字符,并将 k 从栈顶移除。

注意:因为在 Java 中 Integer 是不可变的,需要先弹出栈顶元素,然后加 1,再压入栈顶。

Java版:

class Solution {
    public String removeDuplicates(String s, int k) {
        StringBuilder st = new StringBuilder(s);
        ArrayDeque<Integer> counts = new ArrayDeque<>();
        for (int i = 0; i < st.length(); i++) {
            if (i == 0 || st.charAt(i) != st.charAt(i - 1)) {
                counts.push(1);
            } else {
                int inc = counts.pop() + 1;
                if (inc == k) {
                    st.delete(i - k + 1, i + 1);
                    i = i - k;
                } else {
                    counts.push(inc);
                }
            }
        }
        return st.toString();
    }
}

Python3版:

class Solution:
    def removeDuplicates(self, s: str, k: int) -> str:
        counts = []
        i = 0 
        while i < len(s):
            if i == 0 or s[i] != s[i - 1]:
                counts.append(1)
            else:
                counts[-1] += 1
                if counts[-1] == k:
                    counts.pop()
                    s = s[:i - k + 1] + s[i + 1:]
                    i = i - k
            i += 1
        return s

复杂度分析

  • 时间复杂度:O(n),其中 n 是字符串长度。每个字符只处理一次。

  • 空间复杂度:O(n),栈空间。

解法3:栈重建

如果将计数器和字符都存储在栈中,则不需要修改字符串,只需要根据栈中结果重建字符串即可。

  • 迭代字符串:
  • 如果当前字符与栈顶元素相同,则栈顶元素计数器加 1;否则,计数器设为 1,当前字符压入栈。
  • 如果栈顶元素计数器等于 k,则弹出栈顶元素。
  • 使用栈中元素和计数器构建结果字符串。

Java版:

class Pair {
    int cnt;
    char ch;
    public Pair(int cnt, char ch) {
        this.cnt = cnt;
        this.ch = ch;
    }
}

class Solution {
    public String removeDuplicates(String s, int k) {
        ArrayDeque<Pair> counts = new ArrayDeque<>();
        for (int i = 0; i < s.length(); i++) {
            if (counts.isEmpty() || s.charAt(i) != counts.peek().ch) {
                counts.push(new Pair(1, s.charAt(i)));
            } else {
                if (++counts.peek().cnt == k) {
                    counts.pop();
                }
            }
        }
        StringBuilder st = new StringBuilder();
        while (!counts.isEmpty()) {
            Pair p = counts.pop();
            while (p.cnt-- != 0) {
                st.append(p.ch);
            }
        }
        return st.reverse().toString();
    }
}

Python3版:

class Pair:
    def __init__(self, cnt, ch):
        self.cnt = cnt
        self.ch = ch

class Solution:
    def removeDuplicates(self, s: str, k: int) -> str:
        counts = []
        for ch in s:
            if not counts or ch != counts[-1].ch:
                counts.append(Pair(1, ch))
            else:
                counts[-1].cnt += 1
                if counts[-1].cnt == k:
                    counts.pop()
        st = []
        for x in counts:
            st.append(x.ch * x.cnt )
        return ''.join(st)

复杂度分析

  • 时间复杂度:O(n),其中 n 是字符串长度。每个字符只处理一次。

  • 空间复杂度:O(n),栈空间。

  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值