394.字符串解码

2020-03-27
字符串解码

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

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

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

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

示例:
  • s = "3[a]2[bc]", 返回 "aaabcbc".
  • s = "3[a2[c]]", 返回 "accaccacc".
  • s = "2[abc]3[cd]ef", 返回 "abcabccdcdcdef".
题解:
思路1: 递归
暴力的一层一层解开[]
 
var decodeString = function (s) {
  let fn = (k, str) => {
    let result = ''; // 要返回的字符串
    let l, r; // 记录左右括号的位置
    while (str.indexOf('[') > -1) { // 当当前字符串还有[时 继续处理字符串
      let tmp = 1; // 临时变量 记录当前是否找到闭合的[]
      for (let i = 0; i < str.length; i++) { // 循环字符串
        if (str[i] === '[') { // 当为[时记录l的位置
          l = i;
        }
        else if (str[i] === ']') { // 当第一次出现 ] 时, tmp设为0 也就是找到了第一个闭合的[]
          tmp = 0;
          r = i;
        } else continue;
        if (tmp === 0) { // 当找到了闭合的[]时 ,l, r 分别记录的是[]的左右位置
          let j = 1; // 记录[前面几位是数字
          while (/[0-9]/.test(str[l - (j + 1)]) && l - j >= 0) {
            j++ // 如果[前面一直是数字,则继续往前找
          }
          const k = parseInt(str.slice(l - j, l)); // k是[前面数字的大小
          let sonStr = str.slice(l + 1, r); // sonStr是[]之间的字符串
          str = str.slice(0, l - j) + fn(k, sonStr) + str.slice(r + 1); // 传入的字符串等于 数字左侧的 + []之间和k乘积之后的 + ]之后的
          break; // 每处理完一个[], break出去继续找下一个 直到str中没有[]
        }
      }
    }
    for (let i = 0; i < k; i++) { // k是倍数,要把结果循环k次
      result += str;
    }
    return result; // result是每一个[]处理之后的结果
  }
  return fn(1, s); // s传入 相对于 1[s]的类型
};
思路2: 栈+深度优先搜索
用出栈入栈的思维解开[]
 
var decodeString = function (s) {
  let stock = [], res = '', multi = 0; // stock是辅助栈
  for (let c of s) { // 遍历字符串 s 中每个字符 c;
    if (c === '[') { // 当 c 为 [ 时,将当前 multi 和 res 入栈,并分别置空置 0
      // 记录此 [ 前的倍数 multi 至栈,用于发现对应 ] 后,获取 multi × [...] 字符串
      // 记录此 [ 前的临时结果 res 至栈,用于发现对应 ] 后的拼接操作;
      stock.push([multi, res]); // 进入到新 [ 后,res 和 multi 重新记录。
      multi = 0;
      res = '';
    } else if (c === ']') { // 当 c 为 ] 时,stack 出栈,拼接字符串 res = last_res + cur_multi * res,其中:
      let tmp = stock.pop();
      const last_res = tmp[1]; // last_res是上个 [ 到当前 [ 的字符串,例如 "3[a2[c]]" 中的 a;
      let cur_multi = tmp[0]; // cur_multi是当前 [ 到 ] 内字符串的重复倍数,例如 "3[a2[c]]" 中的 2。
      let ss = res; // ss记录循环后的res
      while(cur_multi > 1) {
        ss += res;
        cur_multi--;
      }
      res = last_res + ss; // res变为 上一次存入栈中的last_res拼接循环后的res
    } else if(/[0-9]/.test(c)) {
      multi = multi * 10 + parseInt(c); // 当 c 为数字时,将数字字符转化为数字 multi,用于后续倍数计算;
    } else {
      res += c; // 当 c 为字母时,在 res 尾部添加 c;
    }
  }
  return res;
}
原文地址:https://www.cnblogs.com/lanpang9661/p/12579917.html