LeetCode #394 Medium

Decode String

Decode String: expand an encoded string of the form k[encoded_string], where the bracketed section repeats exactly k times. Brackets may nest.

Constraints
  • 1 <= s.length <= 30
  • s consists of lowercase English letters, digits, and square brackets.
  • The input is always valid; 1 <= k <= 300.
stringstackrecursion
Open on LeetCode ↗
02

Intuition

Nesting means the inner content must finish before the outer repeat can apply, and 'innermost first' is exactly what a stack gives you. Build the current string as you read; on [ push what you had and the repeat count, then start fresh; on ] multiply the piece you just built and glue it back onto the parent.

How to spot this pattern

Nested, balanced delimiters where the inner scope must complete before the outer one is a stack problem — the same shape as expression evaluation, Basic Calculator, and Valid Parentheses. The recognisable move is pushing the context at the opener and restoring it at the closer, so each level is rebuilt from the inside out.

03

Approach

Try it first

Before reading on: in "3[a2[c]]", which segment must be resolved first, and what two facts about the outer level do you need to remember while working on the inner one? Aim for one pass.

1

What has to be remembered at an opening bracket

When you meet [, you are about to start a new inner segment, but two things about the outer context must survive: the text built so far, and how many times this new segment will repeat. Both go on stacks. The current string then resets to empty so the inner segment builds cleanly. Nothing else about the outer level matters, which is why two stacks are enough no matter how deep the nesting goes.

2

What happens at a closing bracket

A ] means the innermost segment is complete. Pop the repeat count and multiply the segment by it, then pop the saved outer text and append the repeated block to it. That combined value becomes the new current string. Because the pops mirror the pushes exactly, each ] reunites a segment with its own parent — the structure of the brackets is enforced automatically by the stack discipline.

3

Digits and letters between the brackets

Digits must be accumulated rather than read one at a time: 12[a] means twelve, so build the number with num = num * 10 + int(ch) and only use it when the [ arrives. Plain letters simply append to the current string. After the final character, the current string holds the fully decoded result — no extra pass is needed. Time and space are O(n) in the length of the decoded output, which is what dominates when repeat counts are large.

04

Solution & live demo

1class Solution:
2 def decodeString(self, s):
3 count_stack, string_stack = [], []
4 current, num = "", 0
5 for ch in s:
6 if ch.isdigit():
7 num = num * 10 + int(ch)
8 elif ch == "[":
9 count_stack.append(num)
10 string_stack.append(current)
11 current, num = "", 0
12 elif ch == "]":
13 current = string_stack.pop() + current * count_stack.pop()
14 else:
15 current += ch
16 return current
05

Common pitfalls

Reading digits one character at a time

✗ Wrong
num = int(ch)
✓ Right
num = num * 10 + int(ch)

Overwriting instead of accumulating breaks any count of two or more digits: 12[a] keeps only the 2 and produces two copies instead of twelve.

Concatenating in the wrong order on close

✗ Wrong
current = current * count_stack.pop() + string_stack.pop()
✓ Right
current = string_stack.pop() + current * count_stack.pop()

The saved outer text came before the bracket, so it must be the prefix. Reversing the order turns "a2[b]" into "bba" instead of "abb".

Forgetting to reset num after pushing

✗ Wrong
count_stack.append(num)
string_stack.append(current)
current = ""
✓ Right
count_stack.append(num)
string_stack.append(current)
current, num = "", 0

A stale num leaks into the next bracket group, so 2[a]3[b] may apply the wrong multiplier — the count must be consumed and cleared at the same moment it is pushed.

06

Edge cases

No brackets at all, e.g. "abc"

Letters append directly and the stacks stay empty; the input is returned unchanged.

Multi-digit counts, e.g. "12[a]"

Digits accumulate into 12 before the bracket, producing twelve copies rather than one then two.

Nested brackets, e.g. "3[a2[c]]"

The inner 2[c] resolves to 'cc' first, then the outer repeat applies to 'acc'.

Text after a closing bracket, e.g. "2[ab]cd"

The trailing letters append to the already-decoded string, giving 'ababcd'.

Zero repeats, e.g. "0[a]"

Multiplying by zero yields an empty block, which appends harmlessly.

07

Complexity

Time
O(n)
Space
O(n)
n is the length of the decoded output, which dominates the input length when repeat counts are large.