[LeetCode每日一题:2021.3.9] | 刷题打卡

650 阅读2分钟

题目描述

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

给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。

在 S 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

示例:

输入:"abbaca"
输出:"ca"
解释:
例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"

提示:

1 <= S.length <= 20000
S 仅由小写英文字母组成。

链接:leetcode-cn.com/problems/re…

算法思路

模拟

根据题目要求,我们每枚举一个数,就判断它和前面仍存在的数比较,若相等,则删除这两个数。

具体代码的话,我们可以用一个hash表来记录被删去了的数,遍历时,与前面最近的一个未被删除的数进行比较。最后再遍历一遍字符串,将仍然存在的字符记录下来即可。

代码如下:

/**
 * @param {string} S
 * @return {string}
 */
var removeDuplicates = function(s) {
    const n = s.length
    const hash = {}
    for(let i = 1; i < n; ++ i) {
        let j = i - 1
        while(j >= 0 && hash[j]) -- j
        if(s[i] == s[j]) 
            hash[i] = hash[j] = true
    }
    let ans = ""
    for(let i = 0; i < n; ++ i)
        if(!hash[i])
            ans += s[i]
    return ans;
};

时间复杂度:O(n ^ 2)

根据上面的思路,我们可以发现这类似于一个"消消乐"的游戏,如果你经常看我的文章,你会发现每次题目中具有"消消乐"的性质,都可以使用栈的先入先出特性来解决。

实现流程是这样的:我们维护一个栈存储当前未被删除的字符,然后看下个字符是否与栈顶字符相等,若相等则应该将下个字符与当前栈顶的字符都除去,我们弹出栈顶字符即可。

代码如下:

/**
 * @param {string} S
 * @return {string}
 */
Array.prototype.top = function() {
    return this[this.length - 1]
}

var removeDuplicates = function(s) {
    const n = s.length
    const stk = []
    for(let i = 0; i < n; ++ i) {
        if(stk.length && stk.top() === s[i]) stk.pop()
        else stk.push(s[i])        
    }
    return stk.join("")
};

时间复杂度:O(n) 空间复杂度:O(n)

本文正在参与「掘金 3 月闯关活动」,点击查看活动详情