Open azl397985856 opened 3 years ago
/**
@return {string} */ var decodeString = function(s) { let stack = []; // 保存需要 repeat 的字符串 let times = ''; // 乘以的倍数
for (let i = 0, len = s.length; i < len; i++) { let item = s[i];
if (/[0-9]/.test(item)) {
if (i === 0 || /[0-9]/.test(s[i - 1])) {
times += item;
} else {
times = item
}
} else if (item === '[') {
times && stack.push(Number(times));
times = '';
} else if (item === ']') {
var curr = stack.pop();
var temp = '';
while (typeof curr !== 'number') {
temp = curr + temp;
curr = stack.pop();
}
temp = temp.repeat(curr);
stack.push(temp);
} else {
stack.push(item);
}
} return stack.join(''); };
思路
1.栈+迭代
构建辅助栈 stack, 遍历字符串 s 中每个字符 c; 当 c 为数字时,将数字字符转化为数字 multi,用于后续倍数计算; 当 c 为字母时,在 res 尾部添加 c; 当 c 为 [ 时,将当前 multi 和 res 入栈,并分别置空置 00: 记录此 [ 前的临时结果 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。 返回字符串 res。
代码
/**
* 栈+迭代
*/
class Day4LC394V0 {
public String decodeString(String s) {
StringBuilder res = new StringBuilder();
int multi = 0;
LinkedList<Integer> stack_multi = new LinkedList<>();
LinkedList<String> stack_res = new LinkedList<>();
for (Character c : s.toCharArray()) {
if (c == '[') {
stack_multi.addLast(multi);
stack_res.addLast(res.toString());
multi = 0;
res = new StringBuilder();
} else if (c == ']') {
StringBuilder tmp = new StringBuilder();
int cur_multi = stack_multi.removeLast();
for (int i = 0; i < cur_multi; i++) tmp.append(res);
res = new StringBuilder(stack_res.removeLast() + tmp);
} else if (c >= '0' && c <= '9') multi = multi * 10 + Integer.parseInt(c + ""); //记录数字
else res.append(c); //直接添加字符
}
return res.toString();
}
}
复杂度分析
2.递归
总体思路与辅助栈法一致,不同点在于将 [ 和 ] 分别作为递归的开启与终止条件:
当 s[i] == ']' 时,返回当前括号内记录的 res 字符串与 ] 的索引 i (更新上层递归指针位置); 当 s[i] == '[' 时,开启新一层递归,记录此 [...] 内字符串 tmp 和递归后的最新索引 i,并执行 res + multi * tmp 拼接字符串。 遍历完毕后返回 res。
代码
/**
* 递归
*/
class Day4LC394V1 {
public String decodeString(String s) {
return dfs(s, 0)[0];
}
private String[] dfs(String s, int i) {
StringBuilder res = new StringBuilder();
int multi = 0;
while (i < s.length()) {
if (s.charAt(i) >= '0' && s.charAt(i) <= '9')
multi = multi * 10 + Integer.parseInt(String.valueOf(s.charAt(i)));
else if (s.charAt(i) == '[') {
String[] tmp = dfs(s, i + 1);
i = Integer.parseInt(tmp[0]);
while (multi > 0) {
res.append(tmp[1]);
multi--;
}
} else if (s.charAt(i) == ']')
return new String[]{String.valueOf(i), res.toString()};
else
res.append(String.valueOf(s.charAt(i)));
i++;
}
return new String[]{res.toString()};
}
}
复杂度分析
class Day4LC394V0 {
public String decodeString(String s) {
StringBuilder res = new StringBuilder();
int multi = 0;
LinkedList<Integer> stack_multi = new LinkedList<>();
LinkedList<String> stack_res = new LinkedList<>();
for (Character c : s.toCharArray()) {
if (c == '[') {
stack_multi.addLast(multi);
stack_res.addLast(res.toString());
multi = 0;
res = new StringBuilder();
} else if (c == ']') {
StringBuilder tmp = new StringBuilder();
int cur_multi = stack_multi.removeLast();
for (int i = 0; i < cur_multi; i++) tmp.append(res);
res = new StringBuilder(stack_res.removeLast() + tmp);
} else if (c >= '0' && c <= '9') multi = multi * 10 + Integer.parseInt(c + ""); //记录数字
else res.append(c); //直接添加字符
}
return res.toString();
}
}
建立一个栈,遍历字符串,判断每个字符的类型,如果是[则说明后续字母是重复的,如果是]则说明重复字符串结束,需要出栈,剩下的数字和字符直接存储在栈中。
class Solution:
def decodeString(self, s: str) -> str:
stack = []
for char in s:
if char == ']':
repeat = ''
num = ''
while stack and stack[-1] != '[':
repeat = stack.pop() + repeat
stack.pop()
while stack and stack[-1].isdigit():
num = stack.pop() + num
stack.append(int(num) * repeat)
else:
stack.append(char)
return "".join(stack)
T: O(N) S: O(N)
https://leetcode-cn.com/problems/decode-string/
模拟
# 写法一
class Solution:
def decodeString(self, s: str) -> str:
# time s + |s|
# space n
# 单栈模拟
stack = []
for char in s:
if char != ']':
stack.append(char)
else:
# 取出字符
alpha = list()
while stack and stack[-1].isalpha():
alpha.append(stack.pop())
# 数组 -> string
tmp = ""
for i in range(len(alpha) - 1, -1, -1):
tmp += str(alpha[i])
alpha = tmp
# case:
# s = "3[ab]2[bc]"
# stack = ['3','[','a','b']
# alpha = ['b','a']
# tmp = "ab"
# 取出[
if stack and stack[-1] == '[':
stack.pop()
# 取出倍数
multiple = list()
while stack and stack[-1].isdigit():
multiple.append(stack.pop())
# 数组 -> string -> int
tmp = ""
for i in range(len(multiple) - 1, -1, -1):
tmp += str(multiple[i])
multiple = int(tmp)
# 放回 倍数个字符
while multiple > 0:
stack.append(alpha)
multiple -= 1
res = ""
for i in range(0, len(stack)):
res += stack[i]
return res
# 写法二
class Solution:
def decodeString(self, s: str) -> str:
stack = []
res = ""
multi = 0
for c in s:
if c == '[':
stack.append([multi, res])
multi, res = 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
1.待补充
Start traversing string s and process each character based on the following rules:
Case 1) Current character is not a closing bracket ]. Push the current character to stack.
Case 2) Current character is a closing bracket ].
Start decoding the last traversed string by popping the string decodedString and number k from the top of the stack.
Pop from the stack while the next character is not an opening bracket [ and append each character (a-z) to the decodedString. Pop opening bracket [ from the stack. Pop from the stack while the next character is a digit (0-9) and build the number k.
Java Code:
class Solution {
public String decodeString(String s) {
// 3[a2[bc]]
// when meet ] poll out from stack
// a temp list to hold parsed string with in a []
// 注意!!!!k的取值范围 k可能并不是一个digit
Deque<Character> stack = new ArrayDeque<>();
char[] sArr = s.toCharArray();
for (int i = 0; i < sArr.length; i++) {
if (sArr[i] != ']') {
stack.push(sArr[i]);
} else {
List<Character> tempList = new ArrayList<>();
while(!stack.isEmpty() && stack.peek() != '[') {
tempList.add(stack.pop());
}
stack.pop(); // pop out '['
int base = 1;
int num = 0;
while (!stack.isEmpty() && Character.isDigit(stack.peek())) {
num += (stack.pop() - '0') * base;
base *= 10;
}
// reverse order push into stack again
while (num-- > 0) {
for (int j = tempList.size() - 1; j >= 0; j--) {
stack.push(tempList.get(j));
}
}
}
}
char[] result = new char[stack.size()];
int i = stack.size() - 1;
while (!stack.isEmpty()) {
result[i--] = stack.pop();
}
return new String(result);
}
}
复杂度分析
令 n 为数组长度。
通过栈来解决本题 1、通过循环原来的字符串依次将除了']'以外的字符进栈a, 2、如果遇到中括号‘]’就从栈顶依次出栈,用一个临时栈b来保存,直到遇到‘[’,此时栈顶是这段字符串的重复次数, 取出数字并重复之前的临时栈,计算出结果再倒序插入原来的栈a,清空用来保存临时数组的临时栈b 3、然后继续循环,直到S字符串被遍历完
/**
* @param {string} s
* @return {string}
*/
var decodeString = function(s) {
let newZhan = [];
let temp=[]
for(let i=0;i<s.length;i++){
if(s[i]!=']'){
newZhan.push(s[i])
}else{
let time = new Array()
while(newZhan[newZhan.length-1]!='['){
temp.push(newZhan.pop())
}
newZhan.pop()
while(!isNaN(newZhan[newZhan.length-1])){
let tmp = newZhan.pop()
time.push(tmp)
}
time= Number(time.reverse().join(''))
newZhan.push(temp.reverse().join('').repeat(time));
temp.splice(0,temp.length)
}
}
return newZhan.join('');
};
双栈,一个用来记录count,一个用来存储再次遇到 [ 之前已经构建好的字符串。
class Solution {
public String decodeString(String s) {
int n = s.length();
Stack<Integer> numStack = new Stack<>();
Stack<String> strStack = new Stack<>();
StringBuilder builder = new StringBuilder();
int count = 0;
for (int i = 0; i < n; i++) {
char ch = s.charAt(i);
if (Character.isDigit(ch)) {
count = count * 10 + ch - '0';
} else if (ch == '[') {
numStack.push(count);
strStack.push(builder.toString());
count = 0;
builder.setLength(0);
} else if (ch == ']') {
int num = numStack.pop();
StringBuilder temp = new StringBuilder(strStack.pop());
for (int j = 0; j < num; j++) {
temp.append(builder);
}
builder = temp;
} else {
builder.append(ch);
}
}
return builder.toString();
}
}
时间:O(n)
空间:O(n)
function decodeString(S) {
// if(S.length===0) return ""
let stack = []
let num = ''
for (const s of S) {
// 数字可能会多个,注意一下这里的技巧
if (!isNaN(s)) {
num += s
continue
}
if (num) {
stack.push(num)
num = ''
}
// 进栈
if (s !== ']') {
stack.push(s)
continue
} else if (s === ']') {
// 出栈
let str = ''
// 遇见 [ 出栈结束
while (stack.length && stack.slice(-1)[0] !== '[') {
let lastEle = stack.pop()
console.log(lastEle)
str = lastEle + str
}
stack.pop() // 删除 [
let num = +stack.pop()
stack.push(str.repeat(num))
}
}
console.log(stack, 'stack')
return stack.join('')
}
想到类似基本计算器的栈,但是实操没出来。最后自己用递归做的,依次解开括号,得到答案。
class Solution:
def decodeString(self, s: str) -> str:
if "]" not in s:
return s
idx=s.index("]")
j=idx
while j>=0 and s[j]!="[":
j-=1
t=j-1
while s[t].isdigit():
t-=1
k=int(s[t+1:j])
words=s[j+1:idx]
replace=words*k
s_new=s[:t+1]+replace+s[idx+1:]
return self.decodeString(s_new)
时间复杂度:O(n^2) n为字符串长度
空间复杂度:O(n)
学习了官方题解的栈思想,括号匹配这种其实只要一个栈就够了,之前想歪了。改成栈之后只用一次遍历,时间复杂度为O(n)。
class Solution:
def decodeString(self, s: str) -> str:
i=0
stk=[]
while i<len(s):
if s[i]!="]":
stk.append(s[i])
else:
word=""
while stk[-1]!="[":
word=stk.pop()+word
stk.pop()
num=0
k=0
while len(stk)>0 and stk[-1].isdigit():
num=pow(10,k)*int(stk.pop())+num
k+=1
stk.append(word*num)
i+=1
return "".join(stk)
public class Solution {
public String decodeString(String s) {
String res = "";
Stack<Integer> countStack = new Stack<>();
Stack<String> resStack = new Stack<>();
int idx = 0;
while (idx < s.length()) {
if (Character.isDigit(s.charAt(idx))) {
int count = 0;
while (Character.isDigit(s.charAt(idx))) {
count = 10 * count + (s.charAt(idx) - '0');
idx++;
}
countStack.push(count);
}
else if (s.charAt(idx) == '[') {
resStack.push(res);
res = "";
idx++;
}
else if (s.charAt(idx) == ']') {
StringBuilder temp = new StringBuilder (resStack.pop());
int repeatTimes = countStack.pop();
for (int i = 0; i < repeatTimes; i++) {
temp.append(res);
}
res = temp.toString();
idx++;
}
else {
res += s.charAt(idx++);
}
}
return res;
}
}
利用栈思想解决。
class Solution:
def decodeString(self, s: str) -> str:
stack = []
for char in s:
if char != ']':
stack.append(char)
else:
temp_list_str = []
while True:
if stack[-1] == '[':
stack.pop()
break
temp_list_str.append(stack.pop())
temp_list_str.reverse()
temp_list_num = []
while True:
if not stack or not stack[-1].isdigit():
break
temp_list_num.append(stack.pop())
temp_list_num.reverse()
temp_num = ''.join(temp_list_num)
temp_str = ''.join(temp_list_str) * int(temp_num)
stack.append(temp_str)
return ''.join(stack)
递归思想解决
递归入口: 从头开始遍历字符串s。最外层保存一个解析串decoded和一个计数器cnt,当遇到普通字符时,添加到decoded后面;当遇到数字时,添加到cnt后面;当遇到左括号 '[' 时,陷入下一层递归。 下一层也新保存一个解析串decoded和一个计数器cnt,当遇到普通字符时,添加到decoded后面;当遇到数字时,添加到cnt后面;当遇到左括号 '[' 时,再陷入下一层递归。
递归出口: 当遇到右括号 ']' 时,递归结束,返回2个东西:当前这一层括号内的模式串pattern,以及当前右括号的下一个下标index。 回到上一层,在陷入递归的地方拿到pattern和index。该层的解析串decoded后面添加pattern * cnt,重置cnt为空,并把遍历字符串s的指针跳到index位置。
class Solution:
def decodeString(self, s:str, i = 0) -> str:
decoded = ''
cnt = ''
while i < len(s):
# 普通字符,直接拼接到decoded后面
if s[i].isalpha():
decoded += s[i]
i += 1
# 普通数字,直接拼接到cnt后面
elif s[i].isdigit():
cnt += s[i]
i += 1
# 左括号 '[' ,将括号内的字符串重复cnt次,再拼接到decoded后面
# 注意:括号内可能还会嵌套括号,要递归处理
elif s[i] == '[':
# 需要从递归中取2个东西:括号内的模式串,以及右括号的下一个下标index
pattern, index = self.decodeString(s, i+1)
pattern = pattern * int(cnt) # 重复cnt次
decoded += pattern # 拼接到decoded上
cnt = '' # 重置计数器cnt
i = index
# 右括号 ']',说明括号内的模式解析完毕
# 递归结束,返回需要的2个东西:括号内的模式串,以及右括号的下一个下标index
elif s[i] == ']':
return decoded, i + 1
return decoded
java
char[] chars = s.toCharArray();
// 当遇到数字,压入栈,遇到[压入栈,并保存Sting数组,遇到]压出栈并弹出一个数字重复
Stack<Character> stack = new Stack<>();
int length = chars.length;
int tmp = 0;
StringBuffer res = new StringBuffer();
while (tmp < length) {
if (chars[tmp] <= '9' && chars[tmp] >= '0') {
stack.push(chars[tmp]);
} else if (chars[tmp] == '[') {
stack.push(chars[tmp]);
} else if (chars[tmp] == ']') {
// 弹出字符直到遇到[符号
StringBuffer sb = new StringBuffer();
StringBuffer sb2 = new StringBuffer();
char popChar;
while ((popChar = stack.pop()) != '[') {
sb.append(popChar);
}
while (!stack.isEmpty()) {
popChar = stack.peek();
if (popChar >= '0' && popChar <= '9') {
popChar = stack.pop();
sb2.append(popChar);
} else {
break;
}
}
int cycle = Integer.parseInt(sb2.reverse().toString());
sb = sb.reverse();
String appendStr = sb.toString();
for (int i = 1 ; i < cycle ; i++) {
sb.append(appendStr);
}
char[] myChars = sb.toString().toCharArray();
for (int i = 0 ; i < myChars.length ; i++) {
stack.push(myChars[i]);
}
} else {
stack.push(chars[tmp]);
}
tmp++;
}
while (!stack.isEmpty()) {
res.append(stack.pop());
}
System.out.println(res.reverse());
用字符存储需要反复翻转字符,所以我改用了字符串的栈来存储
public String decodeString(String s) {
LinkedList<String> stack = new LinkedList<>();
int index = 0;
while (index < s.length()) {
char tmp = s.charAt(index);
if (tmp >= '0' && tmp <= '9') {
// 是数字,当做整体放入栈中
StringBuffer sb = new StringBuffer();
while(tmp >= '0' && tmp <= '9') {
sb.append(tmp);
tmp = s.charAt(++index);
}
stack.addLast(sb.toString());
} else if (tmp == '[') {
stack.addLast(String.valueOf(tmp));
index++;
} else if (tmp == ']') {
LinkedList<String> sub = new LinkedList<>();
while (!"[".equals(stack.peekLast())) {
sub.addLast(stack.pollLast());
}
Collections.reverse(sub);
stack.pollLast();
int repTime = Integer.parseInt(stack.pollLast());
StringBuffer t = new StringBuffer();
StringBuffer sb2 = new StringBuffer();
for (String tmpStr : sub) {
sb2.append(tmpStr);
}
String o = sb2.toString();
for (int i = 0 ; i < repTime ; i++) {
t.append(o);
}
stack.addLast(t.toString());
index++;
} else {
// 是字母,当做整体放入栈中
StringBuffer sb = new StringBuffer();
while ((tmp >= 'a' && tmp <= 'z') || (tmp >= 'A' && tmp <= 'Z')) {
sb.append(tmp);
if (++index >= s.length()) {
break;
}
tmp = s.charAt(index);
}
stack.addLast(sb.toString());
}
}
StringBuffer res = new StringBuffer();
while(!stack.isEmpty()) {
res.append(stack.pollFirst());
}
return res.toString();
}
时间复杂度O(n) 空间复杂度O(n)
class Solution:
def decodeString(self, s: str) -> str:
stack = []
for c in s:
if c is not ']':
stack.append(c)
else:
rep = ''
while True:
s = stack.pop()
if s == '[':
break
else:
rep += s
k = ''
while True:
k += stack.pop()
if not stack or not(stack[-1] in '0123456789'):
break
for i in range(int(k[::-1])):
for j in range(len(rep)-1, -1, -1):
stack.append(rep[j])
return ''.join(stack)
time complexity: maxK^(count_k)n space complexity: maxK^(count_k)n
class Solution {
public String decodeString(String s) {
return dfs(s, 0)[0];
}
private String[] dfs(String s, int i) {
StringBuilder res = new StringBuilder();
int multi = 0;
while(i < s.length()) {
if(s.charAt(i) >= '0' && s.charAt(i) <= '9')
multi = multi * 10 + Integer.parseInt(String.valueOf(s.charAt(i)));
else if(s.charAt(i) == '[') {
String[] tmp = dfs(s, i + 1);
i = Integer.parseInt(tmp[0]);
while(multi > 0) {
res.append(tmp[1]);
multi--;
}
}
else if(s.charAt(i) == ']')
return new String[] { String.valueOf(i), res.toString() };
else
res.append(String.valueOf(s.charAt(i)));
i++;
}
return new String[] { res.toString() };
}
}
string decodeString(string s)
{
vector<string> stack;
int len = s.length();
int stack_len = 0;
for (int i = 0 ; i < len; i++)
{
if (s[i] != ']')
{
stack.push_back(string(1, s[i]));
stack_len++;
}
else
{
string repeat_str = "";
while(stack_len && stack[stack_len - 1] != "[")
{
repeat_str = stack[stack_len - 1] + repeat_str;
stack.pop_back();
stack_len--;
}
stack.pop_back(); // 弹出'['
stack_len--;
string num = "";
while(stack_len && stack[stack_len - 1] >= "0" && stack[stack_len - 1] <= "9")
{
num = stack[stack_len - 1] + num;
stack.pop_back();
stack_len--;
}
string tmp = "";
for (int j = 0; j < atoi(num.c_str()); j++)
tmp += repeat_str;
stack.push_back(tmp);
stack_len++;
}
}
string res = "";
for (int i = 0; i < stack.size(); i++)
{
res += stack[i];
}
return res;
}
思路: 使用栈,压入栈的思想
代码: Java
class Solution {
public String decodeString(String s) {
StringBuilder res = new StringBuilder();
int multi = 0;
LinkedList
string input分以下几种,数字,char,和左括号,右括号 数字之后必然是左括号,右括号可看作返回字符串的标记 遇到是数字的字符串,把字符串变成数字; 数字之后一定是左括号 左括号之后一定是字符 所以逻辑就变成,遇到数字字符,变成数字N,再把后面括号中的内容读取完(以右括号为终结),返回字符串,重复累加字符串N遍,返回
class Solution {
public:
string decodeString(string s) {
string res;
int i = 0;
return helper(s, i);
}
string helper(string s, int& indx) {
string res = "";
for(;indx<s.size();indx++) {
if(s[indx] == ']') {
break;
}else if(s[indx] < '0' || s[indx] > '9') {
res+= s[indx];
} else {
int count = 0;
while(s[indx] >= '0' && s[indx] <='9') {
count = count * 10 + s[indx] - '0';
indx++;
}
indx++;
string temp = helper(s, indx);
while(count != 0) {
res+=temp;
count--;
}
}
}
return res;
}
};
//递归 var decodeString = function(s) { return recursion(s, 0); }; var recursion = function(s, i){ let res = '', num = ''; while(i < s.length) { if(/[0-9]/.test(s[i])) { num += s[i]; i++; } else if(/[a-z]/i.test(s[i])) { res += s[i]; i++; } else if(s[i] === '[') { const [pattern, nextIndex] = recursion(s, i+1) res += pattern.repeat(Number(num)); num = ''; i = nextIndex; continue; } else if(s[i] === ']') { return [res, i+1] } } return res; }
function decode(str) {
let arr = str.split("");
let res = [];
let temp = "";
let flag = 0;
let encode = false;
while (arr.length > 0) {
let s = arr.pop();
if (encode === true) {
//数字的情况
temp = temp.repeat(Number(s));
encode = false;
flag === 0 ? (res.push(temp), (temp = "")) : null;
} else if (s === "]") {
//右括号
flag++;
} else if (s === "[") {
//左括号
flag--;
encode = true;
} else if (flag == 0) {
//没有括号
res.push(s);
} else {
temp = `${s}${temp}`;
}
}
return res.reverse().join("");
}
使用栈,压入栈,保存字符串
Java
class Solution {
public String decodeString(String s) {
StringBuilder res = new StringBuilder();
int multi = 0;
LinkedList<Integer> stack_multi = new LinkedList<>();
LinkedList<String> stack_res = new LinkedList<>();
for(Character c : s.toCharArray()) {
if(c == '[') {
stack_multi.addLast(multi);
stack_res.addLast(res.toString());
multi = 0;
res = new StringBuilder();
}
else if(c == ']') {
StringBuilder tmp = new StringBuilder();
int cur_multi = stack_multi.removeLast();
for(int i = 0; i < cur_multi; i++) tmp.append(res);
res = new StringBuilder(stack_res.removeLast() + tmp);
}
else if(c >= '0' && c <= '9') multi = multi * 10 + Integer.parseInt(c + "");
else res.append(c);
}
return res.toString();
}
}
O(n)
主要是用栈的思维,先进后出。遇到[
则入栈,遇到]
则出栈,再注意数字部分就可以。
const decodeString = (str) => {
const strStack = []; // 非最小重复部分则入栈
const numStack = []; // 保存数字部分
let resultStr = ''; // 保存每一次的重复部分
let num = 0; // 保存数字
for (const letter of str) {
switch (letter) {
case '[':
// 全部入栈
strStack.push(resultStr);
numStack.push(num);
resultStr = '';
num = 0;
break;
case ']':
// 出栈时需要注意拼接
resultStr = strStack.pop() + resultStr.repeat(numStack.pop());
break;
default:
// 需要特殊处理一下数字部分
if (parseInt(letter, 10) >= 0) {
num = num * 10 + parseInt(letter, 10);
} else {
resultStr += letter;
}
}
}
return resultStr;
};
令 k 为字符串的最大嵌套深度的数字至它外层所有数字部分之积, 则 k 最小位1。
时间复杂度: 最小时间复杂度是O(n),最大时间复杂度是O(n*K),最复杂情形是:100[2[3[4[5[b]]]]]
空间复杂度: 字符串必须是新字符,所以最小空间是O(n),同样取决于K,最大空间是O(n*k)
ps: 我不懂复杂度计算,以上是我瞎猜的,总觉得repeat会消耗空间和时间。
Using a list as a stack, push every character in the string into the stack if it is not a closing bracket.
If we encounter a closing bracket, we need to start pop characters out of the stack to get the repeated string and how many times the string is repeated.
We first pop out the characters and store them into a temp string until we meet a starting bracket. The temp string is what is need to be repeated. We then pop the opening bracket.
Then we pop out the number characters one by one until the last element of the stack is not a numeric character. We then get the number of times to repeat. Use the number and temp string to get the repeated string, then push it back to the stack, since it might still be part of another longer repeating string.
We repeat the steps above go through every character in the provided string. Then the answer is combining all elements in the stack together.
class Solution:
def decodeString(self, s: str) -> str:
stack = []
for char in s:
if char == "]":
tempStr = ""
count = ""
while stack and stack[-1] != "[":
tempStr = stack.pop() + tempStr
#pop the "[" character
stack.pop()
#pop all the numbers from the stack and get the count number
while stack and stack[-1].isnumeric():
count = stack.pop() + count
#get the repeated temp string
repeat = int(count) * tempStr
#push the repeated string to the stack
stack.append(repeat)
else:
stack.append(char)
#get the final answer
res = ""
for i in range(len(stack)):
res += stack[i]
return res
Time Complexity: O(n). Since it needs to go through the string once.
Space Complexity: O(n).
利用入栈和出栈,遍历string
使用语言:Python3
class Solution:
def decodeString(self, s: str) -> str:
res = []
for char in s:
if char == ']':
rep = ''
repCount = ''
while res and res[-1] != '[':
rep = res.pop() + rep
res.pop()
while res and res[-1].isnumeric():
repCount = res.pop() + repCount
res.append(rep * int(repCount))
else:
res.append(char)
return ''.join(res)
复杂度分析 时间复杂度:O(N) 空间复杂度:O(N)
/**
* @param {string} s
* @return {string}
*/
var decodeString = function (s) {
let numStact = [] // 倍数栈
let strStact = [] // 字符栈
let res = ''
let num = 0
for (let i of s) {
if (!isNaN(i)) { // 是否是数字
// * 10是因为可能是多位树
num = num * 10 + Number(i)
} else if (i === '[') {
/*
* 是否遇到‘[’
* 将之前的res和倍数放入对应的栈中
*/
strStact.push(res)
res = ''
numStact.push(num)
num = 0
} else if (i === ']') {
/*
* 是否遇到‘]’
* 获取最后放入栈的字符
* repeat 批量返回res
*/
res = strStact.pop() + res.repeat(numStact.pop())
} else {
res += i
}
}
return res
};
使用双栈来解决、一个用来储存复制多少次、一个用来储存当前需要复制的 字符串
const numStack =[];
const strStack =[];
let resStr = "",num=""
for(let str of s){
if(!isNaN(str))num+=str。//处理 100a 这种情况
// 这个地方是关键、先➕入需要复制的字符串
else if(str==="["){
strStack.push(resStr)
numStack.push(num)
resStr=''
num=""
}
else if(str==="]"){
resStr=strStack.pop()+resStr.repeat(numStack.pop())
}else resStr+=str
}
return resStr
class Solution {
public:
string decodeString(string s)
{
string res = "";
stack <int> nums;
stack <string> strs;
int num = 0;
int len = s.size();
for(int i = 0; i < len; ++ i)
{
if(s[i] >= '0' && s[i] <= '9')
{
num = num * 10 + s[i] - '0'; // 123-->0*10+1-->1*10+2-->12*10+3
}
else if((s[i] >= 'a' && s[i] <= 'z') ||(s[i] >= 'A' && s[i] <= 'Z'))
{
res = res + s[i];
}
else if(s[i] == '[') //将‘[’前的数字压入nums栈内, 字母字符串压入strs栈内
{
nums.push(num);
num = 0;
strs.push(res);
res = "";
}
else //遇到‘]’时,操作与之相配的‘[’之间的字符,使用分配律
{
int times = nums.top();
nums.pop();
for(int j = 0; j < times; ++ j)
strs.top() += res;
res = strs.top(); //之后若还是字母,就会直接加到res之后,因为它们是同一级的运算
//若是左括号,res会被压入strs栈,作为上一层的运算
strs.pop();
}
}
return res;
}
};
var decodeString = function(s) {
const stack = []
let res = ''
let brackets = 0
let repeatStr = ''
let numStr = ''
for (let i = 0; i < s.length; i++) {
if (!isNaN(Number(s[i]))) {
numStr += s[i]
continue
} else if (numStr) {
stack.push(Number(numStr))
numStr = ''
}
if (s[i] !== ']') {
stack.push(s[i])
}
if (s[i] === '[') {
brackets++
} else if (s[i] === ']') {
brackets--
let str = ''
let a = stack.pop()
while (a !== '[') {
str = a + str
a = stack.pop()
}
a = stack.pop()
for (let i = 0; i < a; i++) {
repeatStr += str
}
if (brackets === 0) {
res += repeatStr
} else {
stack.push(repeatStr)
}
repeatStr = ''
} else if (isNaN(Number(s[i])) && brackets === 0) {
res += s[i]
stack.pop()
}
}
return res
};
时间复杂度:O(n), n为s的长度 空间复杂度:O(n)
用的栈,数字和字母封开存放,存放之后,遇到]就取出最顶上的并传递
class Solution {
public String decodeString(String s) {
String k="" ;
String out="" ;
int intK ;
boolean r = true;
String d="" ;
Stack<Integer> stack = new Stack<>();
Stack<String> stack1 = new Stack<>();
for (int i = 0; i < s.length(); i++) {
if(s.charAt(i)=='['){
r=false;
int x = i;
k="";
while (x>0){
if(Character.isDigit(s.charAt(x - 1))){
k= s.charAt(x - 1)+k;
}else {
x=0;
}
x--;
}
stack.add(Integer.parseInt(k));
x = i;
d="";
while (x<s.length()){
if(Character.isDigit(s.charAt(x + 1))||s.charAt(x + 1)==']'){
x=s.length();
}else {
d= d+s.charAt(x + 1);
}
x++;
}
stack1.add(d);
}else
if(s.charAt(i)==']'){
intK=stack.pop();
d=stack1.pop();
String dd="";
for (int j = 0; j < intK; j++) {
dd=dd+d;
}
if(!stack.empty()){
dd = stack1.pop()+dd;
if(i!=s.length()-1&&!Character.isDigit(s.charAt(i + 1))){
int x=i;
while (x<s.length()){
if(Character.isDigit(s.charAt(x + 1))||s.charAt(x + 1)==']'){
x=s.length();
}else {
dd= dd+s.charAt(x + 1);
}
x++;
}
}
stack1.add(dd);
}else {
out=out+dd;
}
if(i<s.length()-1&&!Character.isDigit(s.charAt(i + 1))&&stack.empty()){
int x=i;
while (x<s.length()-1){
if(Character.isDigit(s.charAt(x + 1))){
x=s.length();
}else {
out= out+s.charAt(x + 1);
}
x++;
}
}
}else {
if(!Character.isDigit(s.charAt(i ))&&r){
out =out+s.charAt(i);
}
}
}
return out;
}
}
时间复杂度O(N) 常数有点大
''' 3[a2[c]] st st = 3 [ a 2 [ c ] c 2 st = 3 [ a c c c c a reverse! 3 * (a c c)
acc acc acc
while not [ push all char into stack
meet ] pop all letters -> save to tmpStr pop [ pop all digits -> save to tmpNum reverse(tmpStr) tmpNum * tmpStr -> push into stack
3[a]2[bc] st = 3 [ a a 3 st = aaa2[bc cb 2 cbcb reverse-> bcbc aaa + bcbc
''' from collections import deque from typing import List from collections import OrderedDict from collections import defaultdict import functools import heapq import bisect
class Solution: def decodeString(self, s: str) -> str: if not s: return ""
st = deque()
i = 0
while i < len(s):
# 不能在两个地方 同时对i + 1
if s[i] != ']':
st.append(s[i])
else: # == ]
tmpStr = ""
# error
while st and st[-1].isalpha():
# print(poped)
tmpStr = st.pop() + tmpStr
# get rid of [
if st:
st.pop()
tmpNum = ''
while st and (st[-1].isdigit()):
tmpNum = st.pop() + tmpNum
tmpNum = int(tmpNum)
tmpStr = tmpStr * tmpNum
for ele in tmpStr:
st.append(ele)
# error
i += 1
return "".join(st)
if name == 'main': s = "100[leetcode]"
result = Solution().decodeString(s)
print(result)
https://leetcode.com/problems/decode-string/
]
is the key point, when seeing it, start popping characters from the stack.
[
.LinkedList
to store the letters being popped, always add the letter to the index 0 (head) of the list.[
and dump it.k
k
timesclass Solution {
public String decodeString(String s) {
Stack<Character> stack = new Stack<>();
for(int i = 0; i < s.length(); i++){
char curr = s.charAt(i);
// start to process the encoded string from stack
if(curr == ']'){
List<Character> list = new LinkedList<>();
while(!stack.isEmpty() && stack.peek() != '['){
list.add(0, stack.pop());
}
// pop the '[' from stack and dump it
stack.pop();
// process the digits from stack
int base = 1;
int k = 0;
while(!stack.isEmpty() && Character.isDigit(stack.peek())){
k += Character.getNumericValue(stack.pop()) * base;
base *= 10;
}
// decode the string by generating the sub string k times and push to stack
while(k > 0){
for(char c : list){
stack.push(c);
}
k--;
}
}else{
stack.push(curr);
}
}
StringBuilder result = new StringBuilder();
while(!stack.isEmpty()){
result.append(stack.pop());
}
return result.reverse().toString();
}
}
使用栈对括号进行匹配,每次将字符串与数字入栈,遇到】进行一次出栈,并对字符串进行运算。
class Solution {
public String decodeString(String s) {
StringBuilder res = new StringBuilder();
int multi = 0;
LinkedList<Integer> stack_multi = new LinkedList<>();
LinkedList<String> stack_res = new LinkedList<>();
for(Character c : s.toCharArray()) {
if(c == '[') {
stack_multi.addLast(multi);
stack_res.addLast(res.toString());
multi = 0;
res = new StringBuilder();
}
else if(c == ']') {
StringBuilder tmp = new StringBuilder();
int cur_multi = stack_multi.removeLast();
for(int i = 0; i < cur_multi; i++) tmp.append(res);
res = new StringBuilder(stack_res.removeLast() + tmp);
}
else if(c >= '0' && c <= '9') multi = multi * 10 + Integer.parseInt(c + "");
else res.append(c);
}
return res.toString();
}
}
时间复杂度:O(N) 空间复杂度:O(N)
设置两个辅助栈,一个用于存储数字,一个用于存储encoded_string
(这个栈内最后的内容就是结果)
遇到数字时候,要记得处理连续的数字位,n = n * 10 + cur
最后再压入数字栈
遇到非数字时,分情况讨论:
遇到 右方括号,代表括号闭合,不断弹出栈直到遇到最近的左方括号,在这个过程当中弹出的栈就是要重复k次的encoded string
, 从数字栈中弹出一个元素 , repeat
计算后再放回 encoded_string
栈内
其余情况一股脑入栈即可
var decodeString = function(s) {
let ans = "";
let data = [];
let count = [];
s = s.split('');
for(let i = 0 ; i < s.length ; ++i){
if(isNaN(+s[i])){
if(s[i] === ']'){
let temp = '';
while(data[data.length - 1] !== '[') {
temp += data.pop();
}
data.pop();
let times = count.pop();
data.push(temp.repeat(times));
}else{
data.push(s[i]);
}
}else if(!isNaN(+s[i])){
let num = 0;
while(!isNaN(+s[i])) {
num = +s[i] + num * 10;
++i;
}
count.push(num);
--i;
}
}
return data.reduce((acc , cur) => {
return acc + cur.split('').reverse().join('')
} , '')
};
时间复杂度: O(n)
n 为输入字符串长度
额外空间复杂度: O(max(k)*max(len(s)))
max(k)代表最大的整数大小(重复次数),max(len(s)) 代表最长的encoded_string
字符串
, 栈
循环s的各元素i放入栈res,
当元素i为']'时,从栈res往外取数据并进行字符合并,直到遇到'[';
之后开始数字的合并,直到栈往外取不是数字,最后的字符串=数字项*字符串;
再把算得字符串放入栈中,往下循环s的下各元素
注:
时间复杂度:最坏$O(n^2)$
空间复杂度:$O(n)$
class Solution:
def decodeString(self, s: str) -> str:
res = []
s = '1' + '[' + s + ']'
for i in s:
if i == ']':
x = res.pop()
_i = ''
while x != '[':
_i = x + _i
x = res.pop()
num_str = ''
while True:
if not (res and res[-1].isdigit()):
break
num_str = res.pop() + num_str
_i = int(num_str) * _i
res.append(_i)
else:
res.append(i)
return res[-1]
public String decodeString(String s) {
Stack<Character> stack = new Stack<>();
for(char c : s.toCharArray())
{
if(c != ']')
stack.push(c); // 把所有的字母push进去,除了]
else
{
//step 1: 取出[] 内的字符串
StringBuilder sb = new StringBuilder();
while(!stack.isEmpty() && Character.isLetter(stack.peek()))
sb.insert(0, stack.pop());
String sub = sb.toString(); //[ ]内的字符串
stack.pop(); // 去除[
//step 2: 获取倍数数字
sb = new StringBuilder();
while(!stack.isEmpty() && Character.isDigit(stack.peek()))
sb.insert(0, stack.pop());
int count = Integer.valueOf(sb.toString()); //倍数
//step 3: 根据倍数把字母再push回去
while(count > 0)
{
for(char ch : sub.toCharArray())
stack.push(ch);
count--;
}
}
}
//把栈里面所有的字母取出来
StringBuilder retv = new StringBuilder();
while(!stack.isEmpty())
retv.insert(0, stack.pop());
return retv.toString();
}
class Solution:
def decodeString(self, s: str) -> str:
# 遇到 】 之前不断进行压栈
# 遇到 】 之后开始出栈直到非数字为止,再压栈
stack = []
for c in s:
if c == ']':
pattern = ''
count = ''
while stack and stack[-1] != '[':
pattern = stack.pop() + pattern
stack.pop()
while stack and stack[-1].isdigit():
count = stack.pop() + count
stack.append(int(count) * pattern)
else:
stack.append(c)
return "".join(stack)
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: 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"
class Solution {
public:
string decodeString(string s) {
stack<string> pos;
stack<int> nums;
string res = "";
int sum = 0;
for(int i = 0; i < s.size(); i++)
{
if(s[i] >= '0' && s[i] <= '9')
sum = sum * 10 + s[i] - '0';
else if((s[i] >= 'a' && s[i] <= 'z')||(s[i] >= 'A' && s[i] <= 'Z'))
res += s[i]; //注意大小写,之前第一次提交发现大小写也存在区分
else if(s[i] == '[')
{
nums.push(sum);
sum = 0; //重置 0
pos.push(res);
res = ""; //重置为空字符串
}
else if(s[i] == ']') //此处举例3[a2[c]];
{ //出现[后将3放入nums中,sum重置,res仍为""
sum = nums.top(); //而后再出现[,此时sum=2;res="a",存入pos
nums.pop(); //第一次出现], 此时sum = nums.top() == 2
while(sum) //pos.top = a, res = 'c',输出为res = "acc"
{ //第二次出现],sum = nums.top() == 3;
pos.top() += res; //pos.top = "" 第一次存入的res, res ="acc",
sum--; //画图更好理解,sum经历变化后的值最终始终为0
}
res = pos.top();
pos.pop();
}
}
return res;
}
};
时间复杂度:一次遍历O(s.size), 其中的while循环应该是常数级;
空间复杂度:O(s.size);
(最初想到的是用迭代,但是不太好控制,看了题解后选择使用栈,是在略菜,一边自己动手一边照着改) 思路就是压栈,子字符串压栈,最后依次拿出来,与对应的重复次数做循环叠加后再入栈,作为上一个字符串的子字符串,最后完成全部的字符串
class Solution {
int ptr = 0 ;
public String decodeString(String s) {
LinkedList<String> stk = new LinkedList<String>();
int rep = 1; //rep设为重复次数
StringBuffer c_str = new StringBuffer();//用于压栈的子字符串
while(ptr < s.length()){
char chr = s.charAt(ptr);
if(Character.isDigit(chr)){
String digits = getDigits(s);//从ptr开始,为数字,依次进栈
stk.addLast(digits);
}
else if(Character.isLetter(chr)||chr == '['){
//开始字符压栈
stk.addLast(String.valueOf(s.charAt(ptr++)));
}
else{//右括号
++ptr;//跳过括号,直接进行一个字符串的组装
LinkedList<String> sub = new LinkedList<>();
while (!"[".equals(stk.peekLast())){ // peeklast:检查队尾元素,出栈,遇见了左括号停止
sub.addLast(stk.removeLast());
}
//子字符串翻转
Collections.reverse(sub);
stk.removeLast();//左字符串弹出
rep = Integer.parseInt(stk.removeLast());//取出重复字符串的string形式,转成int
StringBuffer stringBuffer = new StringBuffer();
String sub_str = getString(sub);
while(rep-- > 0){
stringBuffer.append(sub_str);
}
stk.add(stringBuffer.toString());
}
}
return getString(stk);
}
public String getDigits(String s) {
StringBuffer ret = new StringBuffer();
while (Character.isDigit(s.charAt(ptr))) {
ret.append(s.charAt(ptr++));
}
return ret.toString();
}
public String getString(LinkedList<String> v) {
StringBuffer ret = new StringBuffer();
for (String s : v) {
ret.append(s);
}
return ret.toString();
}
}
复杂度分析:
时间复杂度:O(n)
空间复杂度:O(n)
使用两个辅助栈。
一个存储数字,一个存储遇到"["
的瞬时结果(这个栈中的所有瞬时结果合起来就是最最终的结果)。
如果遇到数字,需要处理多位数字的情况,使用mutil
变量将他们连接起来,并在遇到"["
时压入存储数字的栈。
非数字情况,有三种情况:
遇到"["
,我们需要将连接的数字以及连接的瞬时字符串压入栈中
遇到"]"
,括号闭合,我们需要将数字栈顶元素弹出,循环添加括号中出现的字符,并且最后连同存储瞬时结果栈的栈顶元素添加进结果字符串中。
其余的字符串直接添加进res
中就可以了
class Solution {
public String decodeString(String s) {
Stack<Integer> s1 = new Stack<>();
Stack<String> s2 = new Stack<>();
StringBuilder res = new StringBuilder();
int mutil = 0;
for(char c: s.toCharArray()){
if(c == '['){
s1.push(mutil);
s2.push(res.toString());
res = new StringBuilder();
mutil = 0;
}else if(c == ']'){
int nums = s1.pop();
StringBuilder temp = new StringBuilder();
for(int i = 0; i < nums;i++){
temp.append(res);
}
res = new StringBuilder(s2.pop() + temp);
}else if(Character.isDigit(c)){
mutil = mutil * 10 + (c - '0');
}else res.append(c);
}
return res.toString();
}
}
时间复杂度:O(n)
,n代表字符串长度
空间复杂度:O(n)
,栈空间最大存储的是字符串的长度。
class Solution {
public String decodeString(String s) {
StringBuilder strB = new StringBuilder();
StringBuilder strB2 = new StringBuilder();
Deque<Character> stack = new LinkedList<Character>();
for (int i = s.length()-1; i>=0; --i){
char chr = s.charAt(i);
if (chr == ']') stack.push(chr);
else if (Character.isLetter(chr)){
if (stack.size()==0) strB.insert(0, chr);
else {
stack.push(chr);
}
}else { // '['
StringBuilder tmpt = new StringBuilder();
int ptr = i;
do {
ptr--;
if (!Character.isDigit(s.charAt(ptr))){
break;
}
tmpt.insert(0, s.charAt(ptr));
} while (ptr>=1);
int repeat = Integer.parseInt(tmpt.toString());
List<Character> inner = new ArrayList<Character>();
while (stack.peek() != ']'){
inner.add(stack.pop());
}
stack.pop();
for (int r=0; r<repeat;++r){
for (int j = inner.size()-1; j>=0; --j){
stack.push(inner.get(j));
}
}
if (ptr==0 && Character.isDigit(s.charAt(ptr))) break;
else i=ptr+1;
}
}
while (stack.size()>0){
strB2.append(stack.pop());
}
return strB2.toString()+strB.toString();
}
}
用栈处理,遇到 "[",就要开始重复字符串了,另外重复的数字是可能存在多位的, 所以需要往前找到不为数字的那⼀位,把数字转换出来。 最后⽤把 stack ⾥⾯的字符串都串联起来即可
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)
时间复杂度: O(n) 空间复杂度: O(n)
n[string]
表示解析 []
模板里面的内容,然后重复 n
次,即得到 n
个 string
拼接起来的字符串。
根据题意,[]
里面还可以再嵌套 []
,例如 n[m[string]]
。这种情况下,我们得先解析最内层的模板,重复 m
次,然后将 m * string
的结果作为外层模板的解析内容,再重复 n
次。
如果嵌套的层数更多,我们也是得先找到最内层的 []
,就像洋葱一样,一层层剥开,然后再从内到外一层层解析和拼接。这种层层嵌套的描述很容易就让人想到了递归。
按照常规,写递归时不要过多考虑前后的递归函数,想好当前递归函数需要处理些什么就好了。
[
时,说明接下来是一个嵌套模版,开始递归处理。递归处理嵌套模版结束后,我们回到了当前层级,需要的信息有两个,一个是嵌套模版的解码字符串,另一个是嵌套模版的结束坐标。嵌套模版的解码字符串重复 n 次后加到当前层级的解码字符串中,接着从嵌套模版的结束坐标开始继续处理当前层级的字符串。]
时,说明处理当前层级模版的递归可以结束了,返回上一种情况需要的信息,解码字符串以及模版结束的坐标。class Solution {
public:
string decodeString(string s) {
return decodeString(s, 0).first;
}
pair<string, int> decodeString(string s, int cur) {
int k = 0;
string decoded;
while (cur < s.size()) {
// 收集数字
if (isdigit(s[cur])) {
k = k * 10 + s[cur] - '0';
cur++;
}
// 收集字母
else if (isalpha(s[cur])) {
decoded.push_back(s[cur]);
cur++;
}
// 开始解析下一层嵌套
else if (s[cur] == '[') {
pair<string, int> res = decodeString(s, cur + 1);
// 解析完嵌套模式后
while (k-- > 0) {
decoded.append(res.first);
}
k = 0;
cur = res.second;
}
// 结束当前递归
else if (s[cur] == ']') {
return {decoded, cur + 1};
}
}
return {decoded, -1};
}
};
/**
* @param {string} s
* @return {string}
*/
var decodeString = function(s, cur = 0) {
let k = 0;
let decoded = '';
while (cur < s.length) {
if (s[cur] === '[') {
const [str, pos] = decodeString(s, cur + 1);
decoded += str.repeat(k);
k = 0;
cur = pos;
} else if (s[cur] === ']') {
return [decoded, cur + 1];
} else if (/[0-9]/.test(s[cur])) {
k = k * 10 + parseInt(s[cur++]);
} else {
decoded += s[cur++];
}
}
return decoded;
};
可以用递归解决的问题,也可以用循环来解决。
这里我用了正则 /[a-zA-Z]+|[0-9]+|\[|\]/
和 exec()
方法来遍历字符串并把它们拆分成 token
,比如,lz3[ab2[c]]
会被拆分成 lz
, 3
, [
, ab
, 2
, [
, c
, ]
, ]
。
lz
)、数字时,入栈;[
时,入栈,用来标识当前进入一个模板解析了;]
时,说明当前模板遍历完了,我们可以开始解析了。
[
时,说明当前模板解析完成了。字母块 * 次数
重新入栈,这是因为模板是可嵌套的,当前模板外面可能还有一层模板,所以我们要把当前层级的解析结果重新入栈,接着解析外层的模板。/**
* @param {string} s
* @return {string}
*/
var decodeString = function (s) {
const reg = /[a-zA-Z]+|[0-9]+|\[|\]/g;
const stack = [];
const peek = () => stack[stack.length - 1]; // p.s. 不正经栈
while (reg.lastIndex < s.length) {
let token = reg.exec(s)[0];
if (token !== ']') {
// 数字,字母,左括号通通入栈
stack.push(token);
} else {
// 遇到右括号就开始出栈
let str = '';
// [] 中间的就是要重复的模式,把它们全部出栈,拼接起来
while (peek() !== '[') {
str = stack.pop() + str;
}
// 丢掉左括号
stack.pop();
// 左括号前面的一定是模式重复的次数
const num = +stack.pop();
// 把复制操作后的字符串放回栈中,作为外层 [] 模式的一部分
stack.push(str.repeat(num));
}
}
return stack.join('');
};
看到有括号的操作首先想起栈
string decodeString(string s) {
stack <int> nums;
stack <string> str;
int num = 0;
string res = "";
for (int i = 0; i < s.size(); ++i) {
if (s[i] >= '0' && s[i] <= '9') {
num = num * 10 + s[i] - '0';
} else if (s[i] == '[') {
nums.push(num);
num = 0;
str.push(res);
res = "";
} else if (s[i] == ']') {
int time = nums.top();
nums.pop();
for(int j = 0; j < time; ++j) {
str.top() += res;
}
res = str.top();
str.pop();
} else {
res += s[i];
}
}
return res;
}
平铺直叙
class Solution:
def decodeString(self, s: str) -> str:
# res用来模拟栈
res=[]
ans=""
# flag=0代表没有[]未处理
flag=0
Len=len(s)
for i in range(Len):
# 如果是字母且不处于[]中,直接放入答案中
if s[i].isalpha() and flag==0:
ans+=s[i]
continue
# 如果是字母且不等于],直接压入栈
if s[i]!="]":
res.append(s[i])
# flag值的设定,以及处理一个[]
if s[i]=="[":
flag+=1
elif s[i]=="]":
flag-=1
# 找到最近的一个[
index=0
for j in range(len(res)-1,-1,-1):
if res[j]=="[":
index=j
break
# t代表[]的字母
t=""
for j in range(index+1,len(res)):
if res[j].isdigit()==False:
t+=res[j]
# 栈内多余的元素删除
del res[index:len(res)]
# 解决数字问题,例如12,231之类的
count=index-1
while True:
if res[count].isdigit():
count-=1
else:
break
if count<0:
break
# 字母需要重复多少次
num=0
for j in range(count+1,index):
num=num*10+int(res[j])
t=t*num
# 删除使用过的数字,例如3,34之类的,也可以写成 del res[count+1:index]
Len1=len(res)-index+count+1
while len(res)!=Len1:
del res[count+1]
# 直接放入答案,还是压入栈
if flag!=0:
for j in t:
res.append(j)
else:
ans=ans+t
return ans
时间复杂度:O(N^2),但我感觉速度可能要稍微快一点。可能是分析的有问题
空间复杂度:O(N)
C++ Code:
class Solution {
public:
string decodeString(string s) {
string res;
stack<int> stN;
stack<string> stS;
int num = 0;
for (auto& v : s) {
// 持续处理数字
if (isGigit(v)) {
num = num * 10 + (v - '0');
}
// 遇到 "[" 就把维护的数字和字符串各自入栈
else if (v == '[') {
cout << "num: " << num << endl;
stN.push(num);
num = 0;
stS.push(res);
res.clear();
} else if (v == ']') {
// 重复次数
int repeatTimes = stN.top();
stN.pop();
string tmp = stS.top();
stS.pop();
for (int i = 1; i <= repeatTimes; ++i) {
tmp += res;
}
res = tmp;
}
// 维护当前处理到的字符串
else {
res += v;
}
}
return res;
}
bool isGigit(const char& c) {
return c >= '0' && c <= '9';
}
};
令 n 为数组长度。
func decodeString(s string) string {
var stack []uint8
for i := range s {
if s[i] != ']' {
stack = append(stack, s[i])
} else {
var left int
var dup []uint8
var times int
var mul = 1
for j := len(stack) - 1; j >= 0; j-- {
if stack[j] == '[' {
left = j + 1
for i2 := range stack[left:] {
dup = append(dup,stack[left:][i2])
}
j--
for j >= 0 && '0' <= stack[j] && stack[j] <= '9' {
times += int(stack[j]-48) * mul
mul *= 10
j--
}
stack = stack[:j+1]
for times>0 {
stack = append(stack,dup...)
times--
}
break
}
}
}
}
var res string
for i := range stack {
res+=string(stack[i])
}
return res
}
复杂度分析
javascript
/**
* @param {string} s
* @return {string}
*/
var decodeString = function(s) {
const stack = []
let ret = ''
for (let i = 0; i < s.length; i++) {
const cur = s[i]
if (cur !== ']') {
stack.push(cur)
continue
}
// 找括号内的字符串
let sub = ''
while(stack[stack.length - 1] !== '[') {
sub = stack.pop() + sub
}
// remove [
stack.pop()
// 找括号前的数字
let top = stack[stack.length - 1]
let num = ''
while(!isNaN(Number(top))) {
num = stack.pop() + num
top = stack[stack.length - 1]
}
// 重复对应的字符串
sub = sub.repeat(Number(num))
stack.push(...sub)
}
return stack.join('')
};
#define MAX_STACK_SIZE 3000
char * decodeString(char * s){
int len = strlen(s);
char * strStack = malloc(sizeof(char) * MAX_STACK_SIZE);
int top = -1;
for(int i=0; i<len; i++)
{
char c = s[i];
if(c != ']')
strStack[++top] = c;
else
{
char * tmpStack = malloc(sizeof(char) * MAX_STACK_SIZE);
int tmpTop = -1;
while(strStack[top] != '[') //将相应字符串逆序放入中转栈
{
tmpStack[++tmpTop] = strStack[top];
top--;
}
top--; //相当于是将‘[’出栈
char * cpyStr = malloc(tmpTop + 2); //之所以加2,是因为当前的tmpTop值为字符串长度-1,还有一个1是给‘\0’用的
for(int j=tmpTop; j>=0; j--)
cpyStr[tmpTop - j] = tmpStack[j]; //该循环完成后顺便也将tmpStack里的字符逆序了,即还原成原有顺序
cpyStr[++tmpTop] = '\0';
int timesOfStr = 0;
int exp = 0;
while(top>=0 && strStack[top] >= '0' && strStack[top] <= '9') //计算相应字符串的倍数
{
timesOfStr += (strStack[top] - '0') * pow(10, exp);
top--;
exp++;
}
int l = strlen(cpyStr);
for(int j=0; j<timesOfStr; j++) //翻倍相应字符串
for(int n=0; n<l; n++)
strStack[++top] = cpyStr[n];
free(tmpStack);
free(cpyStr);
}
}
strStack[++top] = '\0';
return strStack;
}
时间复杂度:O(n³),其中n为输入字符串长度
空间复杂度:O(1)
自己虽然想到了用两个栈,一个存放数据,一个存放字符串,但是没做下去,看了一篇优秀题解,就主要讲一下他的做法吧。 同样,主要是使用两个栈,一个用于存放数据,一个用于存放字符串; 但是需要注意,只有确定数据是完整的乘积后才存入栈中,字符串也同理,只有是完整的字符串才存入。因此,设置了一个整形num用来代表当前不够完整的数字,以及一个字符串item存放不完整的字符。 开始读取: 1)最简单的: 当读取的字节是’0‘到’9‘的时候(注意读出来的是String型),就把他放到num这个数字临时存储地,需要注意前面进去的需要乘以10再加上当前的数字;(将字符型转化为十进制数字) 当读取的字节是普通字符型(即非数字,非[ 非])的时候,直接放到item这个字符串临时存储地中。 2)处理读取到【】的情况: 当读取的字节为[ 的时候,意味着前面临时存入的num已经是完整的了,可以存入栈中; 同时已经完成的item也可以存入栈中;然后再将两个临时存储地初始化; 当读取字节为]的时候,意味着一个字符串读完了,那么就可以进行乘法处理了(从num_stack中取出刚刚放进去的完整num,作为当前item的倍数进行处理),最后将当前完成的item(之前已经存到item栈中)加到之前已经完成的item后面(字符串可以直接相加而相连)
class Solution {
public String decodeString(String s) {
LinkedList<String> stack_item=new LinkedList<String>();
LinkedList<Integer> stack_num=new LinkedList<Integer>();
int num=0;
StringBuilder item= new StringBuilder();
for(int i =0;i<s.length();i++){
Character c=s.charAt(i);
if(c=='['){
stack_item.addFirst(item.toString());
stack_num.addFirst(num);
num=0;
item=new StringBuilder();
}
else if(c==']'){
StringBuilder temp=new StringBuilder();
int cur_num=stack_num.pop();
for(int j =0; j<cur_num; j++){
temp.append(item);
}
item =new StringBuilder(stack_item.pop()+temp);
}
else if(c>='0'&&c<='9'){
num=num*10+Integer.parseInt(c+"");
}
else{
item.append(c);
}
}
return item.toString();
}
}
时间复杂度o(n) 空间复杂度o(n)
对昨天的越界修改
typedef struct {
int topOfStack;
int capacity;
int * array;
} CustomStack;
CustomStack* customStackCreate(int maxSize) {
CustomStack * s = malloc(sizeof(CustomStack));
if(s == NULL)
{
printf("Out of space!");
return NULL;
}
s->array = malloc(sizeof(int) * maxSize);
if(s->array == NULL)
{
printf("Out of space!");
return NULL;
}
s->capacity = maxSize;
s->array[s->topOfStack] = -1;
return s;
}
void customStackPush(CustomStack* obj, int x) {
if(obj->topOfStack != obj->capacity-1)
{
obj->array[++obj->topOfStack] = x;
}
}
int customStackPop(CustomStack* obj) {
if(obj->topOfStack == -1)
{
printf("Empty stack!");
return -1;
}
return obj->array[obj->topOfStack--];
}
void customStackIncrement(CustomStack* obj, int k, int val) {
int i;
if(k >= obj->capacity)
for(i=0; i<obj->capacity; i++)
obj->array[i] += val;
else
for(i=0; i<k; i++)
obj->array[i] += val;
}
void customStackFree(CustomStack* obj) {
if(obj != NULL)
{
free(obj->array);
free(obj);
}
}
/**
* Your CustomStack struct will be instantiated and called as such:
* CustomStack* obj = customStackCreate(maxSize);
* customStackPush(obj, x);
* int param_2 = customStackPop(obj);
* customStackIncrement(obj, k, val);
* customStackFree(obj);
*/
时间复杂度:除了增量操作为O(max(k, maxSize) )外,其他均为O(1)。
空间复杂度:O(1)
394. 字符串解码
入选理由
暂无
题目地址
https://leetcode-cn.com/problems/decode-string/
前置知识
题目描述
编码规则为: 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"