# 【Day 4】字符串解码
# 题目描述
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: 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".
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/decode-string
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
# 我的回答
https://github.com/leetcode-pp/91alg-1/issues/20#issuecomment-638623652
# 有效的括号
# 20. 有效的括号 (opens new window)
这道题有点难度 先降维打击一下
# 题目描述
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 注意空字符串可被认为是有效字符串。
示例 1:
输入: "()" 输出: true
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/valid-parentheses 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
# 解法一
var isValid = function(s) {
let length = s.length;
if (length % 2) return false;
let leftStack = [];
for (let i = 0; i < length; i++) {
if (s[i] == "(" || s[i] == "[" || s[i] == "{") {
leftStack.push(s[i]);
} else {
let top = leftStack[leftStack.length - 1];
if (
(top == "(" && s[i] == ")") ||
(top == "[" && s[i] == "]") ||
(top == "{" && s[i] == "}")
) {
// console.log(leftStack);
leftStack.pop();
} else {
return false;
}
}
}
return !leftStack.length;
};
# 解法二
解法一的判断明显过多
var isValid = function(s) {
let length = s.length;
if (length % 2) return false;
let leftStack = [];
for (let i = 0; i < length; i++) {
let letter = s[i];
switch (letter) {
case "(": {
leftStack.push(letter);
break;
}
case "[": {
leftStack.push(letter);
break;
}
case "{": {
leftStack.push(letter);
break;
}
case ")": {
if (leftStack.pop() !== "(") return false;
break;
}
case "]": {
if (leftStack.pop() !== "[") return false;
break;
}
case "}": {
if (leftStack.pop() !== "{") return false;
break;
}
}
}
return !leftStack.length;
};
# 回到正题
# 解法一
# 思路
设定两个栈 一个用来保存未用掉的数字,一个用来保存未保存的字母,当遇到数字和字符串累加保存,遇到 [
,将数字和字符串都推入各自的栈,等待遇到]
的时候将字符串和数字都取出来组合成一个新的字符串
# 时间复杂度 O(n) 空间复杂度 O(2n+2)
# 代码
var decodeString = function(s) {
let numStack = [];
let outerStack = [];
let string = "";
let num = 0;
for (const i of s) {
let isNum = !isNaN(i);
if (isNum) {
num += i;
} else if (i === "[") {
numStack.push(num);
num = 0;
outerStack.push(string);
string = "";
} else if (i === "]") {
let k = numStack.pop();
string = outerStack.pop() + string.repeat(k);
} else {
string += i;
}
}
return string;
};
# 解法二
空间复杂度应该还能降低
只用一个栈
,将空间复杂度降低到 O(n+2)
var decodeString = function(s) {
let Stack = [];
let string = "";
let num = 0;
for (const i of s) {
let isNum = !isNaN(i);
if (isNum) {
num += i;
} else if (i === "[") {
Stack.push(num);
Stack.push(string);
num = 0;
string = "";
} else if (i === "]") {
let s = Stack.pop();
let k = Stack.pop();
string = s + string.repeat(k);
} else {
string += i;
}
}
return string;
};
很迷 我优化的不是空间吗
# 参考回答
# 题目地址
# 394. 字符串解码 (opens new window)
# 题目描述
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: 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".
# 前置知识
- 栈
- 括号匹配
# 思路
题目要求将一个经过编码的字符解码并返回解码后的字符串。 题目给定的条件是只有四种可能出现的字符
- 字母
- 数字
- [
- ] 并且输入的方括号总是满足要求的(成对出现),数字只表示重复次数
那么根据以上条件,我们可以利用 stack 来实现这个操作
- 遍历这个字符串 s,判断每一个字符的类型 -- 如果是字母 --> 添加到 stack 当中 -- 如果是数字 --> 先不着急添加到 stack 中 --> 因为有可能有多位 -- 如果是 [ --> 说明重复字符串开始 --> 将数字入栈 --> 并且将数字清零 -- 如果是 ] --> 说明重复字符串结束 --> 将重复字符串重复前一步储存的数字遍
拿题目给的例子s = "3[a2[c]]"
来说:
在遇到 】
之前,我们不断执行压栈操作:
当遇到 】
的时候,说明我们应该出栈了,不断出栈知道对应的【
,这中间的就是 repeatStr。
但是要重复几次呢? 我们需要继续出栈,直到非数字为止,这个数字我们记录为 repeatCount。
而最终的字符串就是 repeatCount 个 repeatStr 拼接的形式。 并将其看成一个字母压入栈中。
继续,后面的逻辑是一样的:
(最终图)
# 代码
JavaScript:
/**
* @param {string} s
* @return {string}
*/
var decodeString = function(s) {
var stack = [];
var factor = ""; // repeat time
for (let i = 0; i < s.length; i++) {
var el = s[i];
if (/[0-9]/.test(el)) {
factor += el;
} else if (el === "[") {
if (factor) {
stack.push(factor - 0);
}
factor = "";
} else if (el === "]") {
var char = stack.pop();
var str = "";
while (typeof char !== "number") {
str = char + str; // note: stack -> LIFO -> the string is reversed
char = stack.pop();
}
stack.push(str.repeat(char));
} else {
stack.push(el);
}
}
return stack.join("");
};
Python:
class Solution:
def decodeString(self, s: str) -> str:
stack = []
for c in s:
if c == ']':
repeatStr = ''
repeatCount = ''
while stack and stack[-1] != '[':
repeatStr = stack.pop() + repeatStr
# pop 掉 "["
stack.pop()
while stack and stack[-1].isnumeric():
repeatCount = stack.pop() + repeatCount
stack.append(repeatStr * int(repeatCount))
else:
stack.append(c)
return "".join(stack)
复杂度分析
- 时间复杂度:$O(N)$,其中 N 为 s 长度。
- 空间复杂度:$O(N)$,其中 N 为 s 长度。