Last Updated: April 3, 2026
We have a string where patterns like k[...] mean "repeat whatever is inside the brackets k times." The twist is that these patterns can be nested. 3[a2[c]] means: first decode the inner 2[c] to get "cc", combine it with the "a" before it to get "acc", and then repeat that whole thing 3 times to get "accaccacc".
So we are dealing with nested structures, similar to how parentheses nest in mathematical expressions. When we see an opening bracket, we need to "remember" what we were building so far and what multiplier to use, go decode the inside, and then come back and apply the multiplier. This nesting behavior is a strong signal that either a stack or recursion will be the right tool.
The key observation is that the innermost brackets should be resolved first, and their result feeds into the outer brackets. This inside-out processing is exactly what a stack gives us naturally.
1 <= s.length <= 30 → The input string is extremely short. Even an O(2^n) approach would work on the input. But the output can be up to 10^5 characters long, so the real cost is in building the decoded string.[1, 300] → Repeat counts can be multi-digit (up to 3 digits). We need to parse numbers like 300, not just single digits.s is guaranteed to be valid → No need to handle malformed inputs. Every [ has a matching ], and every [ is preceded by a number.The most straightforward idea: find the innermost bracket pair (one that contains no other brackets inside it), decode it by repeating the string, replace it in the original string, and repeat until no brackets remain.
This works because the innermost brackets are always safe to decode first. They don't contain any nested structures, so we can just repeat their content and substitute it back. After each substitution, what was previously nested becomes one level less deep.
Think of it like peeling an onion from the inside out. Each pass resolves one layer of nesting.
] and then look backwards for its matching [.[ and the string between [ and ].number[string] with the repeated string.This approach works but rebuilds the entire string on every pass. What if we could process the string in a single left-to-right scan, building the result as we go?
Instead of repeatedly scanning and replacing, we can process the string in one left-to-right pass using a stack. As we walk through the string, we build the current decoded string character by character. When we hit a [, we "save" what we have so far (the current string and the repeat count) by pushing them onto the stack, and start fresh for the inner content. When we hit a ], we pop the saved state, repeat the current string the required number of times, and append it to the saved string.
The stack acts as a memory bank. Every time we enter a new bracket level, we deposit our current progress (the string built so far and the repeat count) into the stack. While inside the brackets, we work on a fresh string. When we exit the brackets, we withdraw our saved progress and combine it with the freshly decoded inner content.
This naturally handles nesting of any depth. For 3[a2[c]], when we hit the inner [, we push what we had ("a" and count 2). We decode "c" inside. When we hit the inner ], we pop and get "a" + "c"2 = "acc". When we hit the outer ], we pop the original empty string and count 3, giving us "acc"3 = "accaccacc".
currentString as empty, and currentNum as 0.currentNum = currentNum * 10 + digit (handles multi-digit numbers like 12 or 300).[, push (currentString, currentNum) onto the stack, then reset currentString to empty and currentNum to 0.], pop (previousString, repeatCount) from the stack. Set currentString = previousString + currentString repeated repeatCount times.currentString.currentString.The stack approach is already optimal in terms of time. But there is an alternative way to think about this: recursion. Instead of manually managing a stack, we can let the call stack do the work.
The structure of this problem is inherently recursive. A valid encoded string is either a sequence of regular characters (base case) or a number followed by [encoded_string] where encoded_string is itself a valid encoded string (recursive case).
So we can write a function that processes characters one by one. When it sees a digit, it reads the full number, expects a [, recursively decodes the content until the matching ], and repeats the result. When it sees a letter, it just appends it. The key trick is using a shared index variable so that when a recursive call returns, the caller knows where it left off in the string.
index that tracks our position in the string.decode():index is within bounds and the current character is not ]:[, recursively decode until ], skip the ], and append the repeated decoded string to result.index.decode() starting at index 0.