title: Decode String slug: decode-string difficulty: medium leetcode_id: 394 leetcode_url: https://leetcode.com/problems/decode-string/ categories: - strings - stack - recursion patterns: - monotonic-stack description: | 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]`. The test cases are generated so that the length of the output will never exceed `10^5`. constraints: | - `1 <= s.length <= 30` - `s` consists of lowercase English letters, digits, and square brackets `'[]'` - `s` is guaranteed to be a valid input - All the integers in `s` are in the range `[1, 300]` examples: - input: 's = "3[a]2[bc]"' output: '"aaabcbc"' explanation: "The pattern 3[a] expands to 'aaa' and 2[bc] expands to 'bcbc', giving 'aaabcbc'." - input: 's = "3[a2[c]]"' output: '"accaccacc"' explanation: "The inner 2[c] expands to 'cc', making 3[acc], which expands to 'accaccacc'." - input: 's = "2[abc]3[cd]ef"' output: '"abcabccdcdcdef"' explanation: "2[abc] becomes 'abcabc', 3[cd] becomes 'cdcdcd', plus 'ef' at the end." explanation: intuition: | Think of this problem like unpacking nested boxes. Each `k[...]` is a box containing a message that needs to be repeated `k` times. The tricky part is that boxes can be nested inside other boxes — you need to unpack the innermost boxes first before you can complete the outer ones. This "last opened, first closed" pattern is exactly what a **stack** excels at. When you encounter an opening bracket `[`, you're entering a new nested level. When you hit a closing bracket `]`, you've completed the innermost pattern and need to expand it before continuing with the outer context. Imagine reading `3[a2[c]]`: - You see `3[` — push your current work aside, start fresh for what's inside - You see `a2[` — push again, start fresh for the innermost part - You see `c]` — you've completed `c`, multiply by `2` to get `cc`, pop back to the previous context - Now you have `acc`, hit `]` — multiply by `3` to get `accaccacc` The stack lets you "pause" your current string-building work, dive into a nested pattern, resolve it, and then resume where you left off. approach: | We solve this using a **Stack-Based Approach**: **Step 1: Initialise data structures** - `stack`: Holds pairs of (previous_string, repeat_count) when we enter a new `[` - `current_string`: The string we're building at the current nesting level - `current_num`: Accumulates multi-digit numbers like `12` or `300`   **Step 2: Iterate through each character** - **If digit**: Accumulate into `current_num` (handle multi-digit numbers with `current_num = current_num * 10 + int(char)`) - **If `[`**: Push `(current_string, current_num)` onto the stack, then reset both to start fresh for the nested content - **If `]`**: Pop from stack, multiply `current_string` by the popped count, and prepend the popped string - **If letter**: Simply append to `current_string`   **Step 3: Return the result** - After processing all characters, `current_string` contains the fully decoded string   The key insight is that we save our "context" (what we've built so far and how many times to repeat the upcoming section) whenever we enter a new nesting level, then restore and combine when we exit. common_pitfalls: - title: Forgetting Multi-Digit Numbers description: | The repeat count `k` can be more than one digit! For example, `12[a]` means repeat `a` twelve times, not `1` followed by `2[a]`. When you encounter a digit, you need to accumulate: `current_num = current_num * 10 + int(char)`. This handles numbers like `123` correctly by building up `1` → `12` → `123`. wrong_approach: "Treating each digit as a separate number" correct_approach: "Accumulate digits: current_num = current_num * 10 + digit" - title: Not Resetting State After Opening Bracket description: | When you push to the stack upon seeing `[`, you must reset `current_string` to empty and `current_num` to `0`. Otherwise, you'll mix content from different nesting levels. For `3[a2[c]]`, after pushing at the first `[`, you need a fresh start to build `a` before encountering `2[c]`. wrong_approach: "Continuing to append to the same string after [" correct_approach: "Reset current_string and current_num after pushing to stack" - title: String Concatenation in Wrong Order description: | When popping from the stack after `]`, the order matters: - `prev_string + (current_string * count)` is correct - `(current_string * count) + prev_string` is wrong The `prev_string` is what came *before* the `k[...]` pattern, so it should stay at the front. wrong_approach: "Appending prev_string after the repeated content" correct_approach: "Prepend prev_string: result = prev_string + current_string * count" - title: Using Recursion Without Tracking Position description: | A recursive approach is valid but requires careful handling of the current position. You need to return both the decoded string *and* the index where you stopped, so the caller knows where to resume. The iterative stack approach avoids this complexity by maintaining state explicitly. key_takeaways: - "**Stack for nested structures**: Whenever you see nested patterns with matching pairs (brackets, parentheses), think stack" - "**Save and restore context**: Push your current state when entering a new level, pop and combine when exiting" - "**Multi-digit number handling**: Always accumulate digits with `num = num * 10 + digit` for robustness" - "**Pattern recognition**: This stack technique applies to many parsing problems — balanced parentheses, expression evaluation, nested HTML tags" time_complexity: "O(n * m) where `n` is the length of the encoded string and `m` is the maximum length of the decoded string. Each character is processed once, but string concatenation may involve copying characters multiple times due to repetition." space_complexity: "O(n + m) for the stack storing intermediate strings and the output string. In the worst case of deeply nested patterns, the stack depth approaches `n`." solutions: - approach_name: Stack is_optimal: true code: | def decodeString(s: str) -> str: stack = [] # Stores (prev_string, repeat_count) pairs current_string = "" current_num = 0 for char in s: if char.isdigit(): # Accumulate multi-digit numbers current_num = current_num * 10 + int(char) elif char == '[': # Save current context and start fresh stack.append((current_string, current_num)) current_string = "" current_num = 0 elif char == ']': # Pop context and apply repetition prev_string, repeat_count = stack.pop() current_string = prev_string + current_string * repeat_count else: # Regular letter - just append current_string += char return current_string explanation: | **Time Complexity:** O(n * m) — We process each character once, but string operations may copy characters multiple times based on repeat counts. **Space Complexity:** O(n + m) — Stack space for nested levels plus the decoded output string. The stack elegantly handles nested patterns by saving context when entering brackets and restoring when exiting. Each `]` triggers a "resolve and combine" operation that builds up the final string from the inside out. - approach_name: Recursion is_optimal: false code: | def decodeString(s: str) -> str: def decode(index: int) -> tuple[str, int]: result = "" num = 0 while index < len(s): char = s[index] if char.isdigit(): # Accumulate the repeat count num = num * 10 + int(char) elif char == '[': # Recurse to decode the nested content decoded, index = decode(index + 1) result += decoded * num num = 0 elif char == ']': # End of current level - return to caller return result, index else: # Regular letter result += char index += 1 return result, index decoded_string, _ = decode(0) return decoded_string explanation: | **Time Complexity:** O(n * m) — Similar to the stack approach, processing each character with potential string repetition. **Space Complexity:** O(n) — Recursion depth proportional to nesting level, plus O(m) for output. The recursive approach mirrors the stack solution but uses the call stack implicitly. Each `[` triggers a recursive call, and each `]` returns to the caller. The key is returning both the decoded string *and* the current index so the caller knows where to resume parsing.