Problem
Given an encoded string where a number followed by a bracketed segment means "repeat that segment that many times", decode the full string. Brackets can be nested, so the encoding can be compactly recursive.
- Input:
s = "3[a2[c]]" - Output:
"accaccacc" - Explanation:
2[c]decodes to"cc", soa2[c]becomes"acc", then3[acc]gives"accaccacc".
Counter-example: "2[ab]3[cd]" โ "ababcdcdcd" โ segments are independent when not nested.
Intuition
At every [ we're about to enter a new segment whose result we'll repeat. We need to remember what came before that bracket so we can prepend it after decoding. A stack lets us save and restore that "outer context" at each nesting level: push the state going in, pop and merge coming out.
Solution โ Stack
Walk the string character by character, maintaining a running string and a running number. When we hit [, freeze the current state onto the stack and reset; when we hit ], thaw the previous state and concatenate the just-decoded segment repeated by its count.
- Initialize an empty stack,
current_string = "", andcurrent_number = 0. - For each character
c:- If
cis a digit, updatecurrent_number = current_number * 10 + digit(c)to handle multi-digit counts. - If
cis[, push(current_string, current_number)onto the stack, then reset both to empty/zero โ we're entering a new scope. - If
cis], pop(prev_string, repeat_count)from the stack; the new current isprev_string + current_string * repeat_count. - Otherwise, append
ctocurrent_string.
- If
- Return
current_string.
1def decodeString(self, s: str) -> str:
2 stack = []
3 current_string = ""
4 current_number = 0
5
6 for char in s:
7 if char.isdigit():
8 current_number = current_number * 10 + int(char) # multi-digit numbers
9 elif char == '[':
10 stack.append((current_string, current_number)) # save outer context
11 current_string = ""
12 current_number = 0
13 elif char == ']':
14 prev_string, repeat_count = stack.pop()
15 current_string = prev_string + current_string * repeat_count # prev comes first
16 else:
17 current_string += char
18
19 return current_stringTime: O(L) where L is the length of the decoded output โ each character is written exactly once.
Space: O(n + d) where n is the input length (strings saved on the stack) and d is the maximum nesting depth (stack frames).
Complexity Summary
| Approach | Time | Space | When to use |
|---|---|---|---|
| Stack | O(L) | O(n + d) | Any case โ this is the standard solution |
Common Mistakes
- Treating numbers as single-digit only โ
"12[ab]"has a two-digit multiplier; always usecurrent_number * 10 + digitto accumulate. - Pushing the wrong thing onto the stack โ you push the state before the bracket (the string accumulated so far and the count for this bracket), not the state inside it.
- Reversing the concatenation order โ it's
prev_string + current_string * count, not the other way around; the outer prefix must come first. - Forgetting to reset
current_numberto 0 after pushing โ without the reset, the next bracket's count will accumulate on top of the old one. - Off-by-one on when to read the number โ the number always appears before its
[, so finalize and push the count at the[, not before.
Related Problems
Valid Parenthesesโ same push/pop bracket logic, simpler payloadLongest Valid Parenthesesโ stack tracking indices of unmatched bracketsEvaluate Reverse Polish Notationโ stack that reduces tokens rather than expanding themAsteroid Collisionโ stack where popping resolves a condition between top and current elementMinimum Add to Make Parentheses Validโ tracking unmatched bracket counts with a stack-equivalent counter