题目描述
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: 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"
解题思路
1. 利用栈
本题中可能出现括号嵌套的情况,比如 2[a2[bc]],这种情况下我们可以先转化成 2[abcbc],在转化成 abcbcabcbc。我们可以把字母、数字和括号看成是独立的 TOKEN,并用栈来维护这些 TOKEN。具体的做法是,遍历这个栈:
- 如果当前的字符为数位,解析出一个数字(连续的多个数位)并进栈
- 如果当前的字符为字母或者左括号,直接进栈
- 如果当前的字符为右括号,开始出栈,一直到左括号出栈,出栈序列反转后拼接成一个字符串,此时取出栈顶的数字(此时栈顶一定是数字,想想为什么?),就是这个字符串应该出现的次数,我们根据这个次数和字符串构造出新的字符串并进栈
代码如下:
class Solution {
private int index = 0;
public String decodeString(String s) {
LinkedList<String> stack = new LinkedList<String>();
while(index < s.length()){
char c = s.charAt(index);
if(Character.isDigit(c)){
int digit = getDigit(s);
stack.addLast(String.valueOf(digit));
continue;
}
if(c == ']'){
StringBuilder tmpRes = new StringBuilder();
//先弹出[xx]中的内容xx
while(!stack.isEmpty() && !stack.peekLast().equals("[")){
tmpRes.append(new StringBuilder(stack.removeLast()).reverse().toString());
}
tmpRes = tmpRes.reverse();
//弹出左括号
stack.removeLast();
//再弹出数字
int digit = Integer.parseInt(stack.removeLast());
//重新拼装结果并重新入栈
StringBuilder sb = new StringBuilder();
for(int i = 0; i < digit; i ++){
sb.append(tmpRes);
}
stack.addLast(sb.toString());
}
else{
stack.addLast(c + "");
}
index ++;
}
//返回最终的结果,弹出栈中所有字符串
StringBuilder decodeString = new StringBuilder();
while(!stack.isEmpty()){
decodeString.append(stack.removeFirst());
}
return decodeString.toString();
}
public int getDigit(String s){
int digit = 0;
char c = s.charAt(index);
while(Character.isDigit(c)){
digit = digit * 10 + (c - '0');
index ++;
c = s.charAt(index);
}
return digit;
}
}
解题记录
- 栈中: "kjkj" "e" "f" 目标:kjkjef
- 弹栈然后拼接字符串再反转得到: f+e+kjkj (反转) jkjkef (不等于kjkjef)
- 应在在弹栈的时候先一步reverse
- f + e + jkjk(反转) kjkjef
复杂度分析
- 时间复杂度:记解码后得出的字符串长度为 SS,除了遍历一次原字符串 ss,我们还需要将解码后的字符串中的每个字符都入栈,并最终拼接进答案中,故渐进时间复杂度为 O(S+|s|),即 O(S)。
- 空间复杂度:记解码后得出的字符串长度为 SS,这里用栈维护 TOKEN,栈的总大小最终与 SS 相同,故渐进空间复杂度为 O(S)。
2. 递归解题
class Solution {
private int index = 0;
private String src;
public String decodeString(String s) {
src = s;
return getString();
}
public String getString(){
if(index == src.length() || src.charAt(index) == ']'){
index ++;//过滤]
return "";
}
char c = src.charAt(index);
int digit = 1;
StringBuilder sb = new StringBuilder();
String ret = "";
if(Character.isDigit(c)){
digit = getDigit(src);
index ++;//过滤[
String str = getString();
for(int i = 0; i < digit; i ++){
sb.append(str);
}
ret = sb.toString();
}
else if(Character.isLetter(c)){
ret = c + "";
index ++;
}
return ret + getString();
}
public int getDigit(String s){
int digit = 0;
char c = s.charAt(index);
while(Character.isDigit(c)){
digit = digit * 10 + (c - '0');
index ++;
c = s.charAt(index);
}
return digit;
}
}