【栈】394. 字符串解码

0 阅读3分钟

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

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

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

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

测试用例保证输出的长度不会超过 105

示例 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"

提示:

  • 1 <= s.length <= 30
  • s 由小写英文字母、数字和方括号 '[]' 组成
  • s 保证是一个 有效 的输入。
  • s 中所有整数的取值范围为 [1, 300]

1. 套娃快递拆箱

假设你收到一个奇怪的快递,里面有很多层层嵌套的盒子:

  • 规则: 看到数字(比如 3),表示接下来的盒子要重复 3 次。看到 [,表示开始进入一个新盒子。看到 ],表示当前盒子处理完了,要把里面的东西拿出来,按次数拼好,交给上一层盒子。

你会怎么记? 因为盒子可能嵌套(大盒套小盒),你得拿个记事本,把还没处理完的“任务”先记下来。

  1. 遇到数字: 先把数字存起来(比如 3)。

  2. 遇到 [ (进新盒子):

    • 当前已经拼好的字符串当前的数字一股脑儿扔进“备忘录(栈)”里。
    • 然后清空手里的活,开始记录这个新盒子里面的内容。
  3. 遇到字符: 直接记在手里。

  4. 遇到 ] (拆完一个盒子):

    • 从备忘录(栈)里弹出最近的一次任务。
    • 把刚才手里拼好的内容重复 N 次,贴在弹出来的“前缀字符串”后面。

2. 代码实现(JavaScript)

JavaScript

/**
 * @param {string} s
 * @return {string}
 */
var decodeString = function(s) {
    let stack = [];     // 备忘录:存放 [当前倍数, 之前的字符串]
    let currStr = "";   // 当前正在处理的字符串
    let num = 0;        // 当前正在记录的倍数

    for (let char of s) {
        if (char >= '0' && char <= '9') {
            // 如果是数字(注意处理多位数,比如 10[a]num = num * 10 + Number(char);
        } else if (char === '[') {
            // 进盒子了!把手里的存货(之前的字符串和倍数)扔进备忘录
            stack.push([currStr, num]);
            // 清空手头工具,准备接纳新盒子里的内容
            currStr = "";
            num = 0;
        } else if (char === ']') {
            // 盒子拆完了!
            let [prevStr, repeatCount] = stack.pop();
            // 把现在的字符串重复 N 次,接在老字符串后面
            currStr = prevStr + currStr.repeat(repeatCount);
        } else {
            // 普通字母,直接接在手里
            currStr += char;
        }
    }

    return currStr;
};

3. 逻辑总结

记住这四个“动作”:

  • 数字: 攒倍数(num = num * 10 + char)。
  • 左括号 [ 既然要进入“子问题”了,就把“父问题”的现场(已有的字符串和倍数)存入栈中保护起来。
  • 右括号 ] 一个子问题结束了。从栈里取出父问题的现场,把子问题的结果重复一下,合到父问题上。
  • 字母: 搬砖,直接拼在当前字符串后面。

举例 3[a]2[bc] 的过程:

  1. 遇到 3num = 3
  2. 遇到 [,把 ["", 3] 存入栈,currStr 变回空。
  3. 遇到 acurrStr = "a"
  4. 遇到 ],取出 ["", 3],把 "a" 重复 3 次,得到 currStr = "aaa"
  5. 后面同理处理 2[bc],最后拼成 "aaabcbc"

这样处理,无论套娃有多少层(3[a2[c]]),栈都会帮你自动排好序!