welcome to my blog
LeetCode Top 100 Liked Questions 394. Decode String (Java版; Medium)
题目描述
Given an encoded string, return its decoded string.
The encoding rule is: k[encoded_string], where the encoded_string inside the square brackets is being repeated exactly k times.
Note that k is guaranteed to be a positive integer.
You may assume that the input string is always valid; No extra white spaces, square brackets are well-formed, etc.
Furthermore, you may assume that the original data does not contain any digits and that digits are only for those repeat numbers, k.
For example, there won't be input like 3a or 2[4].
Examples:
s = "3[a]2[bc]", return "aaabcbc".
s = "3[a2[c]]", return "accaccacc".
s = "2[abc]3[cd]ef", return "abcabccdcdcdef"
第一次做; 栈; 难点:括号的嵌套; 核心:res状态的变化; 对四种情况的处理; 见注释分析
import java.util.Stack;
class Solution {
public String decodeString(String s) {
Stack<String> resStack = new Stack<>();
Stack<Integer> repeatNum = new Stack<>();
int rnum = 0;
String res = "";
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (ch == '[') {
resStack.push(res);
repeatNum.push(rnum);
res = "";
rnum = 0;
} else if (ch == ']') {
int n = repeatNum.pop();
String tmp = resStack.pop();
res = tmp + repeatString(res, n);
} else if (ch >= '0' && ch <= '9') {
rnum = 10 * rnum + ch - '0';
} else {
res = res + ch;
}
}
return res;
}
private String repeatString(String str, int n) {
String curr = "";
for (int i = 0; i < n; i++)
curr += str;
return curr;
}
}
LeetCode题解; 最优解
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;
}
}
力扣题解; 最优解; 栈
辅助栈法
本题难点在于括号内嵌套括号,需要从内向外生成与拼接字符串,这与栈的先入后出特性对应。
算法流程:
构建辅助栈 stack, 遍历字符串 s 中每个字符 c;
1.当 c 为数字时,将数字字符转化为数字 multi,用于后续倍数计算;
2.当 c 为字母时,在 res 尾部添加 c;
3.当 c 为 [ 时,将当前 multi 和 res 入栈,并分别置空置 00:
记录此 [ 前的临时结果 res 至栈,用于发现对应 ] 后的拼接操作;
记录此 [ 前的倍数 multi 至栈,用于发现对应 ] 后,获取 multi × [...] 字符串。
进入到新 [ 后,res 和 multi 重新记录。
4.当 c 为 ] 时,stack 出栈,拼接字符串 res = last_res + cur_multi * res,
其中:last_res是上个 [ 到当前 [ 的字符串,例如 "3[a2[c]]" 中的 a;cur_multi是当前 [ 到 ] 内字符串的重复倍数,例如 "3[a2[c]]" 中的 2。
返回字符串 res。
复杂度分析:
时间复杂度 O(N)O(N),一次遍历 s;
空间复杂度 O(N)O(N),辅助栈在极端情况下需要线性空间,例如 2[2[2[a]]]
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();
}
}
力扣题解; 递归; 写的也很好!
总体思路与辅助栈法一致,不同点在于将 [ 和 ] 分别作为递归的开启与终止条件:
当 s[i] == ']' 时,返回当前括号内记录的 res 字符串与 ] 的索引 i (更新上层递归指针位置);
当 s[i] == '[' 时,开启新一层递归,记录此 [...] 内字符串 tmp 和递归后的最新索引 i,并执行 res + multi * tmp 拼接字符串。
遍历完毕后返回 res。
复杂度分析:
时间复杂度 O(N)O(N),递归会更新索引,因此实际上还是一次遍历 s;
空间复杂度 O(N)O(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() };
}
}