删除字符串中的所有相邻重复项 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"
链接:
1209. 删除字符串中的所有相邻重复项 II - 力扣(LeetCode) (leetcode-cn.com)
解题思路
思路一: 暴力解法
算法:
- 记录字符串的长度
- 遍历字符串:
如果当前字符与前一个相同,计数器加 1;否则,重置计数器为 1
如果计数器等于 k,删除这 k 个字符
3. 如果字符串的长度被改变,从头开始重新遍历字符串
实现代码如下:
/**
* @param {string} s
* @param {number} k
* @return {string}
*/
var removeDuplicates = function(s, k) {
let res = s, len = -1;
while (len != res.length) {
len = res.length;
for (let i = 0, count = 1; i < res.length; ++i) {
if (i == 0 || res[i] != res[i - 1]) {
count = 1;
} else if (++count == k) {
res = res.slice(0, i - k + 1) + res.slice(i + 1)
break;
}
}
}
return res;
}
思路二:记忆计数
从方法一中可以看出,如果为每个字符设置计数器,就不必每次删除完字符后从头开始。这种方法具有线性复杂度,但需要额外空间存储字符的计数器。
算法:
1. 初始数组 counts。
2. 遍历字符串:
如果当前字符与上一个字符相等,令 counts[i] = counts[i - 1] + 1;否则,令 counts[i] = 1。
如果 counts[i] = k,删除这 k 个字符,令 i = i - k。
实现代码如下:
/**
* @param {string} s
* @param {number} k
* @return {string}
*/
var removeDuplicates = function (s, k) {
let res = s,
counts = [];
for (let i = 0; i < res.length; ++i) {
if (i == 0 || res.charAt(i) != res.charAt(i - 1)) {
counts[i] = 1;
} else {
counts[i] = counts[i - 1] + 1;
if (counts[i] == k) {
res = res.slice(0, i - k + 1) + res.slice(i + 1);
i = i - k;
}
}
}
return res;
};
时间复杂度:O(n),其中 n 是字符串长度。每个字符仅被处理一次。
空间复杂度:O(n)
思路三:栈
跟「LeedCode 1047: 删除字符串中的所有相邻重复项」一样,只是现在每次入栈 k-1 个,栈头的 k-1 个元素的第一个如果与当前准备入栈的元素相同,则代表k个元素是一样的,则无需入栈
/**
* @param {string} s
* @param {number} k
* @return {string}
*/
var removeDuplicates = function(s, k) {
if(s.length <= 1) {
return s;
}
const stack = [];
for (const ch of s) {
let prev = stack.pop();
if (!prev || prev[0] !== ch) {
stack.push(prev);
stack.push(ch);
} else if (prev.length < k - 1){
stack.push(prev + k)
}
}
return stack.join("");
};
时间复杂度: O(n),其中 n 是字符串的长度
空间复杂度: O(n)