leetcode-1957-删除字符使字符串变好

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

题目地址

一个字符串如果没有 三个连续 相同字符,那么它就是一个 好字符串 。

给你一个字符串 s ,请你从 s 删除 最少 的字符,使它变成一个 好字符串 。

请你返回删除后的字符串。题目数据保证答案总是 唯一的 。   示例 1:

输入: s = "leeetcode"
输出: "leetcode"
解释:
从第一组 'e' 里面删除一个 'e' ,得到 "leetcode" 。
没有连续三个相同字符,所以返回 "leetcode" 。
复制代码

示例 2:

输入: s = "aaabaaaa"
输出: "aabaa"
解释:
从第一组 'a' 里面删除一个 'a' ,得到 "aabaaaa" 。
从第二组 'a' 里面删除两个 'a' ,得到 "aabaa" 。
没有连续三个相同字符,所以返回 "aabaa" 。
复制代码

示例 3:

输入: s = "aab"
输出: "aab"
解释: 没有连续三个相同字符,所以返回 "aab" 。
复制代码

提示:

  • 1 <= s.length <= 105
  • s 只包含小写英文字母。

\

解题思路-正则

本题我第一反应是使用正则,因为使用正则编写代码更简单,可读性,可维护性更强,而且通常正则的效率比自己实现对应逻辑更高。
因为本题给定字符串中只包含小写字母,而且要保证没有三个连续相同的字符,又要删除最少的字符,所以我们使用正则匹配连续 3 个及以上的相同字符,把它们替换为两个该字符即可。

代码实现

var makeFancyString = function(s){
    return s.replace(/([a-z])\1{2,}/g,(x) => {
        return x.substring(0,2)
    })
}
复制代码

代码提交后通过了本题,但是效率并不高,用时方面只击败了 22% 的用户,所以我转而改用编写逻辑解题。

扫描二维码关注公众号,回复: 14196956 查看本文章

解题思路-题意编码

首先创建结果字符串 res 为空串,然后遍历输入字符串的每个位置,如果当前字符 s[i],它的下一位 s[i+1],它的下两位 s[i+2] 三者相同,则跳过,否则将结果字符串累加上当前字符 s[i]

代码实现

var makeFancyString = function(s){
    const len = s.length
    let res = ''

    for(let i = 0;i<len;i++){
        if(i<len-2 && s[i]===s[i+1] && s[i+1]===s[i+2]){
            continue
        }
        res += s[i]
    }

    return res
}
复制代码

这一版代码提交后达到了最优解的用时和内存消耗。\

思考

这促使我思考正则和编写逻辑的区别。
相对本题而言,正则需要匹配 3 个及以上的相同字符,然后根据回调函数替换为目标结果,对编译原理有了解的小伙伴应该知道,编译过程就是一个个读取输入字符,而正则我理解也是类似的原理,所以它在不停的读取输入字符的时候,要回过头去看之前的两个或者更多是不是相同的,直到下一个字符不同,然后再把 3 个或者更多的相同字符替换为 2 个相同字符。而这种不停回溯和判断的过程相比第二种题解的代码,显然效率会更低一些。\

但是这并不意味着使用正则比自己编写逻辑效率低,在通常情况下,正则依然是更优的选择。\

所以讨论最优的算法,如果脱离具体的问题,都是耍流氓。这就像通常快排就是最优的排序算法,但是如果都是整数,我们可以使用计数排序或者基数排序,快排是 O(nlogn) 的时间复杂度,后两者是 O(n) 的时间复杂度。但是通常情况下,快排是最好的排序算法。

至此我们就完成了 leetcode-1957-删除字符使字符串变好

如有任何问题或建议,欢迎留言讨论!

猜你喜欢

转载自juejin.im/post/7102394759662010376