【題目】*394. 字符串解碼
給定一個經過編碼的字符串,返回它解碼後的字符串。
編碼規則爲: 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”.
【解題思路1】單棧
用棧,碰到數字、字母、左中括號都壓入棧中,碰到右括號開始彈出,先彈出拿到字符串,再拿到數字(重複次數),把這一段轉成字符串壓入棧中,繼續執行,最後把棧內存的reverse一下
class Solution {
int ptr;
public String decodeString(String s) {
LinkedList<String> stk = new LinkedList<String>();
ptr = 0;
while (ptr < s.length()) {
char cur = s.charAt(ptr);
if (Character.isDigit(cur)) {
// 遇到數字,進棧
String digits = getDigits(s);
stk.addLast(digits); //addLast()將指定元素追加在此列表的末尾
} else if (Character.isLetter(cur) || cur == '[') {
// 遇到字母或者左括號,進棧
stk.addLast(String.valueOf(s.charAt(ptr++)));
} else {
++ptr;
LinkedList<String> sub = new LinkedList<String>();
//遇到右括號開始出棧,一直出棧知道遇到左括號
while (!"[".equals(stk.peekLast())) {
sub.addLast(stk.removeLast());
}
//將出棧的字母反轉
Collections.reverse(sub);
// 左括號出棧
stk.removeLast();
// 此時棧頂爲當前 sub 對應的字符串應該出現的次數
int repTime = Integer.parseInt(stk.removeLast());
StringBuffer t = new StringBuffer();
String o = getString(sub);
// 構造重複n次的字符串
while (repTime-- > 0) {
t.append(o);
}
// 將構造好的字符串入棧
stk.addLast(t.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();
}
}
class Solution {
public static String decodeString(String s) {
char[] chs = s.toCharArray();
//用 Object
Stack<Object> stack = new Stack<>();
// 計算中括號前的數字是多少,不一定是一位數。
int num = 0;
for (char c : chs) {
if (Character.isDigit(c)) {
// 1. 數字則直接計算
num = num * 10 + c - '0';
} else if (c == '[') {
// 2. 左括號, 先要把前面的數字放進去, 左中括號不用入棧
stack.push(num);
num = 0;
} else if (c == ']') {
// 3. 右括號, 出棧, 獲取局部字符串再根據前面的數字得到乘次數再放入stack
String str = popAndGetString(stack);
int times = (int) stack.pop();
String temp = String.join("", Collections.nCopies(times, str));
stack.push(temp);
} else {
// 4. 正常字符, 放String類型
stack.push(String.valueOf(c));
}
}
return new StringBuilder(popAndGetString(stack)).reverse().toString();
}
// 這邊一種情況是,前面可能已經變成正序的了,但是後面還有,後面來了,然後在這個方法中reverse一下就又變反了
// 那我乾脆只在最終結果處reverse,其他過程不reverse
private static String popAndGetString(Stack<Object> stack) {
StringBuilder sb = new StringBuilder();
while (!stack.isEmpty() && stack.peek() instanceof String) {
sb.append(stack.pop());
}
return sb.toString();
}
}
【解題思路2】雙棧
一個數字棧,一個字符串棧
出棧時遇到左括號,去數字棧取出一個數字
class Solution {
public String decodeString(String s) {
StringBuffer ans=new StringBuffer();
Stack<Integer> multiStack=new Stack<>();
Stack<StringBuffer> ansStack=new Stack<>();
int multi=0;
for(char c:s.toCharArray()){
if(Character.isDigit(c)){
multi=multi*10+c-'0';
}else if(c=='['){
ansStack.add(ans);
multiStack.add(multi);
ans=new StringBuffer();
multi=0;
}else if(Character.isAlphabetic(c)){
ans.append(c);
}else{
StringBuffer ansTmp=ansStack.pop();
int tmp=multiStack.pop();
for(int i=0;i<tmp;i++)ansTmp.append(ans);
ans=ansTmp;
}
}
return ans.toString();
}
}