在问 · 算法题解

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

题目描述

输入字符串 s 和整数 k。

一次操作从 s 中选出 k 个连续且相同的字母并删掉,删除处左右两侧随后拼在一起。

不断操作,直到再也找不到可删的部分。返回最终的字符串。题目保证结果唯一。

示例 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"

解释:逐对删去相邻重复字母后,只剩 ps。

数据范围

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

解题思路

和 1047 一样用栈,但栈里存“字符 + 连续次数”。读到的字符与栈顶字符相同就把次数加 1,次数达到 k 就整个弹出;否则压入 [c, 1]。弹出后栈顶变成更早的一段,它的计数还在,后面的同字符可以接着累加,连锁消除自动完成。

为什么正确

栈从底到顶是已扫描前缀完全消除后的结果(按连续段压缩),相邻两段字符不同,每段次数都小于 k。

复杂度分析

时间 O(n),空间 O(n)。

易错点

每次删除后从头重新扫描会变成 O(n^2/k);栈里必须记录计数,否则无法在 O(1) 内判断栈顶是否已有 k 个。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def removeDuplicates(self, s: str, k: int) -> str:
        stack = []
        for c in s:
            if stack and stack[-1][0] == c:
                stack[-1][1] += 1
                if stack[-1][1] == k:
                    stack.pop()
            else:
                stack.append([c, 1])
        return ''.join(c * cnt for c, cnt in stack)

载入编辑器,自己跑一遍 →

栈与堆 专题的其他题目

查看 栈与堆 全部题目 →