【栈&队列】LeetCode 394. 字符串编码【中等】
示例 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. 构建辅助栈stack,遍历字符串s中每个字符c;
当c为数字时,将数字字符转化为数字multi,用于后续倍数计算;
当c为字母时,在res尾部添加c;
当c为“[”时,将当前 multi 和 res 入栈,并分别 置空 和 置0 :
记录此“[”前的临时结果res至栈,用于发现对应“]”后的拼接操作;
记录此“[”前的倍数multi至栈,用于发现对应“]”后,获取multi * [...]字符串;
进入到新“[”后,res和multi重新记录。
当c为“]”时,stack出栈,拼接字符串 res = last_res + cur_multi * res,其中:
last_res是上个“[”到当前“[”的字符串,例如 "3[a2[c]]"
中的 a
;
cur_multi
是当前 [
到 ]
内字符串的重复倍数,例如 "3[a2[c]]"
中的 2
。
2. 返回字符串res。
时间复杂度: O(N),一次遍历s
;
空间复杂度:O(N),辅助栈在极端情况下需要线性空间,例如 2[2[2[a]]]。
class Solution: def decodeString(self, s: str) -> str: stack, res, multi = [], "", 0 for c in s: if c == '[': stack.append([multi, res]) res, multi = "", 0 elif c == ']': cur_multi, last_res = stack.pop() res = last_res + cur_multi * res elif '0' <= c <= '9': multi = multi * 10 + int(c) else: res += c return res
示例演示一遍,就更加清晰了,梳理出三条线:分别对于字母,数字,左右边界括号的处理逻辑!
方法二:递归解法
总体思路与辅助栈法一致,不同点在于“[”和“]”分别作为递归的开始与终止条件:
当 s[i] == ']' 时,返回当前括号内记录的res字符串与']' 的索引i(更新上层递归指针位置);
当 s[i] == '[' 时,开启新一层递归,记录此[...]内字符串tmp和递归后的最新索引i,并执行res + multi * tmp拼接字符串。
遍历完毕后返回res。
时间复杂度:O(N),递归会更新索引,因此实际上还是一次遍历s。
空间复杂度:O(N),极端情况下递归深度将会达到线性级别。
class Solution: def decodeString(self, s: str) -> str: def dfs(s, i): res, multi = "", 0 while i < len(s): if '0' <= s[i] <= '9': multi = multi * 10 + int(s[i]) elif s[i] == '[': i, tmp = dfs(s, i + 1) res += multi * tmp multi = 0 elif s[i] == ']': return i, res else: res += s[i] i += 1 return res return dfs(s,0)