[路飞]_程序员必刷力扣题: 394. 字符串解码

172 阅读4分钟

394. 字符串解码

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。

示例 1:

输入: s = "3[a]2[bc]"
输出: "aaabcbc"

示例 2:

输入: s = "3[a2[c]]"
输出: "accaccacc"

示例3:

输入: s = "2[abc]3[cd]ef"
输出: "abcabccdcdcdef"

示例4:

输入: s = "abc3[cd]xyz"
输出: "abccdcdcdxyz"

正则

思路

使用正则来匹配字符串中的 数字[字符串]

不考虑嵌套问题,我们首先匹配到的肯定是一个满足正则的内部的一串编码,

如4[b3[a]] 中的3[a]

我们把3[a] 正常展开变成 aaa 来替换原字符串中的3[a],很容易我们可以想到replace方法

接下来只需要重复替换,直到所有的[]都被解开即可

  • 正则:/\d+[[a-z]+]/
  • 循环条件 reg.test(newS),只要能匹配到 数组[字符串] 就继续执行
  • 将匹配到的字符串查分成,循环次数'num' 以及需要循环的字符串'str',拼接并替换

最后返回新的字符串即可

var decodeString = function (s) {
    var reg = /\d+\[[a-z]+\]/
    var newS = s
    while (reg.test(newS)) {
        newS = newS.replace(reg, function (res) {
            res = res.slice(0, -1)
            var result = res.split('[')
            var num = result[0]
            var str = result[1]
            var newStr = ''
            while (num) {
                newStr += str
                num--
            }
            return newStr
        })
    }
    return newS
};

栈的思想

思路

我们来遍历整个字符串并分别处理不同的字符

需要生命几个变量 stack:栈用来保存操作的步骤 num:用来保存当前匹配到的数字 str:用来保存当前匹配到的字符串

开始遍历:

  • 如果是数字 : 则保存在num中,因为数字不仅仅为个位数,所以需要num * 10 + item * 1

  • 如果是'[' : 则代表需要进栈操作,将数字和字符串入栈[num,str],数字是后续字符串需要重复的次数,str是需要拼接在字符串前面的一部分;入栈后清空num和str,继续遍历

  • 如果是']': 则代表需要出栈,此时一定已经匹配到当前的字符串str(并非入栈的那个str),出栈的元素stackItem,0位保存着数字num,1位保存着需要拼接在最前面的字符串preStr

    • 接下来就是拼接字符串的过程,将str重复num次,再拼接到preStr之后
    • 继续遍历
  • 如果'a-z'的字符 : 则拼接在str上

至此完成字符串的解码操作

var decodeString = function (s) {
    var stack = []
    var num = 0
    var str = ''
    for (var i = 0; i < s.length; i++) {
        var item = s[i];
        if (!isNaN(item)) {
            num = num * 10 + item * 1
        } else if (item === '[') {
            stack.push([num, str])
            num = 0
            str = ''
        } else if (item === ']') {
            var stackItem = stack.pop()
            var num = stackItem[0]
            var temp = ''
            while (num > 0) {

                temp += str
                num--
            }
            str = stackItem[1] + temp
        } else {
            str += item
        }
    }
    return str
};

递归的思想

思路

我们需要重新写一个递归的函数recursion, 接受两个参数 s:字符串 i:当前的位置 声明num:保存匹配到的数字,同上num = num * 10 + item * 1 声明str用来保存当前匹配到的字符串 如果匹配到']' 会返回当前的str以及遍历到的位置i(后续接着遍历从i开始) 如果循环完毕则直接返回全部拼接完成的str即可

然后从i的位置开始遍历字符:

  • 如果遇到的是数字; 则保存在num中(num = num * 10 + item * 1)
  • 如果是'[': 则递归调用函数recursion并传入 1.原字符串s和 2.当前位置的下一位i+1
    • 拿到返回的字符串保存在temp中以及递归返回的位置信息index,将temp重复num次拼接在当前str后面
    • 因为递归函数已经遍历过字符串的后续一部分,所以要改变当前的i为index
  • 如果是']': 则返回匹配到的str以及当前位置i

最后遍历完毕会完整的拼接出str,返回str即可

var decodeString = function (s) {
    function recursion(s,pos) {
        var num = 0
        var str = ''
        for (var i = pos; i < s.length; i++) {
            var item = s[i];
            if (!isNaN(item)) {
                num = num * 10 + item * 1
            } else if (item === '[') {
                var res = ''
                var [temp,index] = recursion(s,i+1)
                 while (num > 0) {
                    res += temp
                    num--
                }
                str += res
                i=index
            } else if (item === ']') {
                return [str,i]
            } else {
                str += item
            }
        }
        return str
    }
    return recursion(s,0)
};