题意:
用特定的规则解码字符串,规则是将中括号内的字符串按照中括号前的数字n重复n次。
分析:
我们来分析这个问题,我们首先来思考一种解决办法,for-if,遍历一边字符串,遇到即处理,动态的生成结果。因为这种一遍遍历动态处理的方法一般来说是最好的,所以我们不进行太多分析,直接考虑这种方法的可行性。
来,我们遍历可能遇到四种组分:字母字符,数字字符,前中括号,后中括号。
可能遇到三种情况:数字+中括号+加括号里的字符,数字+中括号+...+括号里面有括号,字符。
我们只需要记录数字(注意可能不止一位),遇到字符就顺序存储起来(stringbuilder),然后重复添加到结果。但是对于括号里面套括号的情况,就决定了我们要利用栈(因为要先处理最里层括号的内容)
所以,比如:a b 3 [ d f 4 [ t y ] ] j k.
1 所以遇到字符就放入零时sb,遇到数字或循环结束就将sb放入结果。
2 遇到数字就给零时变量存储,
3 遇到前中括号就入栈,
4 遇到后中括号就将前中括号出栈,这时候发现,第一步是不正确的,因为括号重叠的关系,字符串有可能后面才放入结果,所以需要一个栈,数字也需要栈。
小结:遇到字符就放入零时变量,直到数字或者结束,就放入结果。而对于数字,意味着括号,这时候数字和字符串入栈,遇到后括号就出栈(括号是无意义的,不存储,只做判断)。
public class Solution {
public String decodeString(String s) {
StringBuilder sb = new StringBuilder();
Stack<Integer> intStack = new Stack<>();
Stack<StringBuilder> strStack = new Stack<>();
int num = 0;
char[] cs = s.toCharArray();
for(int i=0; i<cs.length; i++){
if(Character.isDigit(cs[i])){
num = num* 10 + cs[i] - '0'; //数字可能不止一位
}else if(cs[i] == '['){
intStack.push(num);
strStack.push(sb);
sb = new StringBuilder();
num = 0;
}else if(cs[i] == ']'){
StringBuilder tmp = sb; //最里面的
sb = strStack.pop(); //外一层的
for(int j = intStack.pop(); j>0 ;j--){
sb.append(tmp);
}
}else{
sb.append(cs[i]);
}
}
return sb.toString();
}
}
反思回顾:对于这个问题的分析,其实应该忽略很多不重要的信息,抓住动态的一般过程。
动态的一般过程(核心本质)在于括号,举个例子:
StringA [ StringB [ StringC ] StringD ] StringE
对于以上,我们需要将k个StringC连到StringB后面,然后再连上StringD,然后将k个这个结果连到StringA后面,然后连上StringE.
说明遍历到StringC的时候,AB已经存储在栈中了(说明遇到前括号应该讲字符串存储在栈中并更新为空),取出栈顶连上k个C(说明遇到后括号应该从栈顶取出一个字符串),然后连上StringD....
所以 1 每次遇到前括号就将当前字符串存入栈中,并清空字符串
2 每次遇到后括号就取出栈顶,连上k个当前字符串,继续遍历。
再回顾:其实我们编程就是要找到一种方法(算法),我们宏观的一般化的考虑这种方法的一般子问题的逻辑完备性,而不用考虑忽略的其他子问题。
比如 ........[ .......] ........
我们不用管前括号前面是什么,只要知道在栈中就可以了
我们不用管前括号后括号之间是什么,只需要把n个它连在栈中取出来字符串(前面的)的后面即可
我们不用管后括号的后面是什么只需要继续遍历就可以了。
所以,我们推断出。
遇到前括号就要放入栈,遇到后括号就要取出栈连上,动态的模拟好这个过程就可以了。