Problem
Given an encoded string, return its decoded string.
The encoding rule is: k[encoded_string]
, where the encoded_string
inside the square brackets is being repeated exactly k
times. Note that k
is guaranteed to be a positive integer.
You may assume that the input string is always valid; there are 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 will not be input like 3a
or 2[4]
.
Examples
Example 1:
Input: s = "3[a]2[bc]"
Output: "aaabcbc"
Example 2:
Input: s = "3[a2[c]]"
Output: "accaccacc"
Example 3:
Input: s = "2[abc]3[cd]ef"
Output: "abcabccdcdcdef"
Solution
Nested bracket looks like a bit of problem and solution. In eg. 2, we have 3[a2[c]]
= 3[acc]
. So, Basically we have to first multiply string with most nested bracket, and then outer bracket. This points to recursive or stack usage.
Method 1 - Using Stack
So, we can take a stack. Now consider the string - s = 54[ab6[cd]]
We will keep on adding the chars to stack, till we find closing ]
, because that is the time we have to solve the problem.
So, we iterate on s
:
Now, we encounter first closing parenthesis ]
.So, we pop out all chars till we find opening parenthesis [
. So, we pop out cd
from stack.
Now, we keep popping from stack till chars are digit. We get 6
is number, and multiply cd
by 6 and put it back in stack, i.e. 6*cd
.
Now we continue again, and we get last ]
, so now we have 54*(ab+6(cd))
as answer.
Code
Java
Using 1 Stack
public String decodeString(String s) {
Stack<Character> stack = new Stack<>();
for (char c: s.toCharArray()) {
if (c != ']') {
stack.push(c); //push everything but ]
} else {
//step 1:
//if you find a closing ] then
//retrieve the string it encapsulates
StringBuilder sb = new StringBuilder();
while (!stack.isEmpty() && Character.isLetter(stack.peek()))
sb.insert(0, stack.pop());
String sub = sb.toString(); //this is the string contained in [ ]
stack.pop(); //Discard the '[';
//step 2:
//after that get the number of
// times it should repeat from stack
sb = new StringBuilder();
while (!stack.isEmpty() && Character.isDigit(stack.peek()))
sb.insert(0, stack.pop());
int count = Integer.valueOf(sb.toString()); //this is the number
//step 3:
//repeat the string within the [ ] count
//number of times and push it back into stack
while (count > 0) {
for (char ch: sub.toCharArray())
stack.push(ch);
count--;
}
}
}
//final fetching and returning the value in stack
StringBuilder retv = new StringBuilder();
while (!stack.isEmpty())
retv.insert(0, stack.pop());
return retv.toString();
}
Using 2 stacks - 1 for count and other for answer
Some modifications may be needed while implementing.
- For eg. When we insert 54 above, and pop out, we get 45. Like wise for strings as well.
- Its good to separate numbers and strings in separate stacks, as we dont have to do parsing again and again
- Its good to use StringBuilder in java
public String decodeString(String s) {
Stack<Integer> count = new Stack<>();
Stack<String> result = new Stack<>();
int i = 0;
result.push("");
while (i < s.length()) {
char c = s.charAt(i);
if (c >= '0' && c <= '9') {
int start = i;
while (s.charAt(i + 1) >= '0' && s.charAt(i + 1) <= '9') i++;
count.push(Integer.parseInt(s.substring(start, i + 1)));
} else if (ch == '[') {
result.push("");// push a new string
} else if (ch == ']') {// update and multiply existing string
String str = result.pop();
StringBuilder sb = new StringBuilder();
int times = count.pop();
for (int j = 0; j < times; j += 1) {
sb.append(str);
}
result.push(result.pop() + sb.toString());
} else {
result.push(result.pop() + ch); // update existing string
}
i += 1;
}
return result.pop();
}