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)
};