编码规则为: 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”.
/**
* 解法一
*
* 利用2个栈,一个数字栈numStack,一个字母栈strStack
* 遍历字符串
* 1、字符为数字,解析数字(注意连续数字的情况)存入 num
* 2、字符为字母,拼接字母 存入 str
* 3、字符为左括号,把之前得到的数字 num 和 字母 str 分别压栈,然后把数字重置为0,字母字符串重置为空串
* 4、字符为右括号,数字栈栈顶数字出栈,作为重复次数 n,字母栈栈顶字母出栈,作为前缀字母字符串去拼接 str 字母变量,总共拼接 n 次,拼接后的新字母串给 str
*
* 例如:
* 2[abc]3[cd]ef
* ↑
* 遇到左括号,把数字 num=2 和 字母 str="" 入栈,并且 num 和 str 重置
* | | | |
* | | | |
* |_2_| |_""_|
* numStack strStack
*
* 2[abc]3[cd]ef
* ↑
* 遇到左括号,num=0 str="abc",numStack 和 strStack 栈顶元素出栈 str = strStack.pop() + str \* numStack.pop() = "" + "abc" * 2 = "abcabc"
* | | | |
* | | | |
* |___| |___|
* numStack strStack
*
* 2[abc]3[cd]ef
* ↑
* 遇到右括号,数字 num=3 和 字母 str="abcabc" 入栈,并且 num 和 str 重置
* | | | |
* | | | |
* |_3_| |_abcabc_|
* numStack strStack
*
* 2[abc]3[cd]ef
* ↑
* 遇到左括号,num=0 str=cd,numStack 和 strStack 栈顶元素出栈 str = "abcabc" + "cd" * 3 = "abcabccdcdcd"
* | | | |
* | | | |
* |_3_| |_abcabc_|
* numStack strStack
*
* 遍历结束,最终结果 str="abcabccdcdcdef"
*/
package leetcode;
import java.util.Stack;
public class leetcode_394 {
public static String decodeString(String s) {
Stack<String> stack = new Stack<>();
Stack<Integer> nums = new Stack<>();
StringBuilder res = new StringBuilder();
// res = "";
StringBuilder t = new StringBuilder();
int num = 0;
for(int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
// 如果遇到数字(数字范围可能是比较大),入栈
if(ch >= '0' && ch <= '9') {
num = num * 10 + ch - '0';
}else if(ch == '['){
//遇到"[",将倍数入栈,就把之前的字符串t入栈,并将num清零,重新创建新的字符串t用于存放下一个需要加倍的新串
if(num > 0) {
nums.push(num);
}
stack.push(t.toString());
//清零+重新创建新的待加倍的字符串
t = new StringBuilder();
num = 0;
} else if((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z' )) {
// 如果遇到字母,拼接到距离"["最近的当前待加倍的字符串t中
t.append(ch);
} else if(ch == ']') {
// 遍历如果遇到"]",从字符串栈中取出一个字符串,从数字栈取出一个数字,将字符串进行加倍
//sb 存放去掉这层k[]后,再外面一层[]中的结果
StringBuilder sb = new StringBuilder();
String str = stack.pop();
sb.append(str);
int number = nums.pop();
for(int j = 0; j < number; j++) {
sb.append(t);
}
// 加倍后的字符串存放到[]外层的待加倍字符串,继续扫描,看当前]后面是什么字符
t = sb;
}
}
return t.toString();
}
public static void main(String[] args) {
System.out.println(decodeString("3[a]2[bc]"));
}
}
总体思路与辅助栈法一致,不同点在于将 [ 和 ] 分别作为递归的开启与终止条件:
复杂度分析:
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() };
}
}
其他好理解的思路:
https://leetcode-cn.com/problems/decode-string/solution/java-gua-hao-pi-pei-wen-ti-yong-zhan-by-joseph-4/