给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: 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".
此题关键难点在于中括号的嵌套
针对包含中括号的嵌套问题,一般都用栈来辅助解决。此题也不例外。
定义两个辅助栈,一个用来记录循环数字,一个用来记录要循环的字符串。
在循环外部定义数字变量num,和一个字符串cur,分别用来记录循环数字和字符串。
遍历一边字符串:
1、当当前字符为数字时:

num = num*10 + s[i] - '0';//记录数字

2、当当前字符为普通字符时,记录当前字符:

cur += s[i];

关键在以下遇到括号时的处理
3、当遇到左括号时:
此时表示数字已经记录完毕,当前数字进栈即可,对于字符串cur也进行一次进栈,防止整个字符串开头是没有编码过的字符串开头的,像fe3[lk]这样。如果不是也直接压栈,压入一个空字符串后面相加的时候不影响。
压入后数字清空,字符串清空,去重新记录后续要编码的的字符串。

                numS.push(num);
                strS.push(cur);
                num = 0;
                cur.clear();

4、当遇到右括号时该如何处理(最重要的情况)。
此时已经记录完成了要编码的字符串,遇到右括号进行数字栈弹栈,还原当前的编码字符串,即进行循环次数的编码还原。再将字符串栈顶的元素弹栈,和当前已经还原编码的字符串相连作为cur,此时就是为了处理多重嵌套的问题。当没有括号嵌套时,也没有关系,因为遇到左括号就压了一次栈,这时候也是把之前已经还原好的编码压栈记录了。
最后还原好的cur就是结果。
还是利用了左括号和右括号的对齐与压栈和进栈相互对应,压栈时就把当前已经还原好的结果压入栈,弹栈时,就是把原先还原好的结果连上新的刚还原好的字符串。

class Solution {
public:
    string decodeString(string s) {
        string res = "";
        if(s.length() == 0) return res;
        stack<int> numS;
        stack<string> strS;
        int num = 0;
        string cur = "";
        for(int i=0;i<s.length();i++){
            if(s[i] >= '0' && s[i] <= '9'){
                num = num*10 + s[i] - '0';
            }else if(s[i] == '['){
                numS.push(num);
                strS.push(cur);
                num = 0;
                cur.clear();
            }else if((s[i] >= 'a' && s[i] <= 'z') || (s[i] >= 'A'  && s[i] <='Z')){
                cur += s[i];
            }else if(s[i] == ']'){
                string tmp = "";
                for(int i=0;i<numS.top();i++){
                    tmp += cur;
                }
                numS.pop();
                cur.clear();
                cur = strS.top() + tmp;
                strS.pop();
            }
        }
        return cur;
    }
};