Given an encoded string, return it's decoded string.
The encoding rule is: k[encoded_string]
, where the encoded_string inside the square brackets is being repeated exactly k times. Note thatk is guaranteed to be a positive integer.
You may assume that the input string is always valid; No extra white spaces, square brackets are well-formed, etc.
Furthermore, you may assume that the original data does not contain any digits and that digits are only for those repeat numbers, k. For example, there won't be input like 3a
or2[4]
.
Examples:
s = "3[a]2[bc]", return "aaabcbc". s = "3[a2[c]]", return "accaccacc". s = "2[abc]3[cd]ef", return "abcabccdcdcdef".
这一题思维难度不大,很显然是考察stack的使用,主要是注意细节上的处理,如果一些情况考虑的不够周到,debug可能会话费比较多的时间。
思路:
使用两个stack,一个(1)用来存储系数,一个(2)用来存储字母和括号。用一个循环遍历整个字符串就可以了,基本思路和polish notation非常类似。
按顺序,一个一个的字符遍历,具体方式如下:
- 遇到系数,将系数入栈1(这里的系数可能是多位的,所以要一直检测到数字字符结束,比如:10000);
- 遇到左括号[,入栈2;
- 遇到字符,将后面所有字符入栈2,比如:接下来在字符串是,aaab2[ac....,则将aaab入栈;
- 遇到右括号],这一步就稍微有点复杂。循环出栈2,直到遇到左括号[,就停止出栈。比如:stack2=["x","[","a","b"],则将ba[,按顺序出栈,然后把里面的字符拼接起来,括号去掉,拼接得到的字符是“ab”。然后,将栈1的一个系数出栈(假设系数为3),根据系数循环复制相同的字符串,得到“ababab”,再把复制后的字符再次入栈2。此时栈2的内容是,stack2=["x","ababab"]。
- 直到遍历结束,按顺序拼接栈2中的所有字符串,返回结果即可。
public class Solution {
public String decodeString(String s) {
Stack<Integer> staNumbers = new Stack<>();
Stack<String> staMarks = new Stack<>();
char[] cArr = s.toCharArray();
for (int i = 0; i < cArr.length; i++) {
char c = cArr[i];
if (c >= '0' && c <= '9') {
// if the number is like 10000, which is more than 1 digit
StringBuilder sbNumber = new StringBuilder();
while (i < cArr.length && cArr[i] >= '0' && cArr[i] <= '9') {
sbNumber.append(cArr[i]);
i++;
}
i--;
staNumbers.push(Integer.parseInt(sbNumber.toString()));
} else if (c == '[') {
staMarks.push("[");
} else if (c == ']') {
StringBuilder sbNew = new StringBuilder();
while (true) {
StringBuilder sb = new StringBuilder(staMarks.pop());
if (sb.toString().equals("[")) {
break;
} else {
sbNew.insert(0, sb);
}
}
int nLoopTime = staNumbers.pop();
StringBuilder sbNewNew = new StringBuilder();
for (int j = 0; j < nLoopTime; j++) {
sbNewNew.append(sbNew);
}
staMarks.push(sbNewNew.toString());
} else {
StringBuilder sb = new StringBuilder();
while (i < cArr.length && cArr[i] >= 'a' && cArr[i] <= 'z') {
sb.append(cArr[i]);
i++;
}
staMarks.add(sb.toString());
i--;
}
}
// get all string in staMarks
StringBuilder sb = new StringBuilder();
while (!staMarks.isEmpty()) {
sb.insert(0, staMarks.pop());
}
return sb.toString();
}
}
我把代码中Stack2的类型从String改为StringBuilder以后,发现还变慢了。我推测是因为leetcode的测试用例可能非常极端(如:a[a[a[a[a[a[a[a[a]b]b]b]b]b]......),需要入栈的内容太多,String和StringBuilder对象都很多的情况下,其实没有太大的性能提升。并且,String的某些地方可能还进行了优化,所以这个改动不但没有必要,可能还造成了性能的下降。