首页 > 编程语言 > 详细

算法题:消除字符串中全部的b和连续的ac

时间:2020-04-25 16:07:25      阅读:241      评论:0      收藏:0      [点我收藏+]

最近碰到了一道面试题,虽然不难但是临试没想出好的解法,记录下来以作分享。

题目:消除字符串中全部的b和连续的ac

用例:

  • ‘aabbc‘ -> ‘a‘
  • ‘aaabbbccc‘ -> ‘‘
  • ‘abcdcba‘ -> ‘dca‘

注意结合用例理解这个题目的意思,转化后的字符串中不能有任何b和连续的ac,而不是仅对初始值进行一次转换。

暴力法

既然最后得到的字符串中不能有任何b和连续的ac,那么我们可以很容易地想到使用正则连续地进行处理,直到处理前后的字符串相同,可以很容易地写出下面的代码:

function solution (str) {
  const reg = /ac|b/g
  let strCopy = str
  do {
    str = strCopy
    strCopy = str.replace(reg, ‘‘)
  } while (strCopy !== str)
  return strCopy
}

但是暴力法显然不够好,它每次重复地去执行替换,对于aaaaaccccc这种字符串,需要执行5次。

那么有没有更好的方法呢?通过观察我们发现其实需要替换的字符序列必定符合{n个a}{m个b}{n个c}(m, n不都为0)这种格式。b我们可以先不去管它,先从格式开头的a入手。那么如果找到了a,怎么知道后面的字符序列中有没有c出现呢?而c出现的个数是否能跟a的个数匹配呢?我们可以先保存连续a的数量,然后如果后面出现了符合格式的c,则减少a的个数,直到a耗尽或者格式匹配失败。

存储a的解法

function solution(str) {
    let countA = 0  // 连续a的个数
    let result = ‘‘
    for (let i = 0; i < str.length; i++) {
        if (str[i] === ‘a‘) {
            countA++
        } else if (str[i] === ‘b‘) {
            continue
        } else if (str[i] === ‘c‘) {
            if (countA === 0) {
                result += ‘c‘
            } else {
                countA--
            }
        } else {
            // 遇到其他字符,则保存的a需要释放
            while (countA) {
                result += ‘a‘
                countA--
            }
            result += str[i]
        }
    }
    // 最后需要释放所有保存的a
    while (countA) {
        result += ‘a‘
        countA--
    }
    return result
}

存储a的解法有点类似于栈,遇到a入栈,遇到c出栈,遇到abc之外的字符排空栈。

这是一种时间复杂度O(n)的解法,但是在遇到类似aaaaaad这种字符串的时候,它还不够好,因为最后保存的a都要释放出来,有额外的时间开销。

双指针的解法

这是本题较好的一种解法,设两个指针cur和loc分别从头开始出发,cur每次移动一格,另一个指针loc保留当前的操作位置,如果cur指向的字符是c且loc指向的是a,则将loc回移一位(ac抵消了),如果遇到其他非b的字符,则将loc处的字符置为cur处的字符,一直进行直到到cur到达字符串尾部,此时取字符串开头到loc指针之间的子串即为本题的解。这种解法妙就妙在loc处的字符是即时更新的,一些边界条件都自动消除了。

画一个图更好理解一点,比如有字符串abeabcdaabbcg,它经过处理后应该得到aedag,下面是操作过程的图解:

技术分享图片

这种方法在C++, Java中是可以实现in-place更新的,但Javascript字符串是不可变的,所以体现不出来。

function solution(str) {
    let result = str.split(‘‘)
    let location = -1
    for (let i = 0; i < str.length; i++) {
        let cur = str[i]
        if (cur === ‘c‘ && location >= 0 && result[location] === ‘a‘) {
            location --
        } else if (cur !== ‘b‘) {
            result[++location] = cur
        }
    }
    return result.slice(0, location + 1).join(‘‘)
}

最后做个技术总结,这道题难度不大,考察的是对字符串算法的理解,双指针、栈、动态规划等思想在字符串算法问题中还是有很多应用的,还是要通过学习去总结归纳。

算法题:消除字符串中全部的b和连续的ac

原文:https://www.cnblogs.com/SteelArm/p/12773014.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!