Decode String
Stacks of (count, prefix); on each `]` apply the multiplication and concatenate back to the outer prefix.
Problem#
Decode a string formatted as k[encoded] where k is a positive integer and encoded is a string. Repeat encoded exactly k times. Brackets can nest.
Examples#
"3[a]2[bc]"→"aaabcbc""3[a2[c]]"→"accaccacc""2[abc]3[cd]ef"→"abcabccdcdcdef"
Constraints#
1 <= s.length <= 30,scontains only lowercase letters, digits, and[ ].
Approach#
Two stacks: one for prior counts, one for prior prefixes. Parse digits to form a multi-digit count. On [, push (currentCount, currentPrefix) and reset. On ], repeat the current prefix by the popped count and append to the popped prefix. Letters append to the current prefix.
Solution#
class Solution {public: string decodeString(string s) { stack<int> counts; stack<string> prefixes; string cur; int k = 0; for (char c : s) { if (isdigit(c)) { k = k * 10 + (c - '0'); } else if (c == '[') { counts.push(k); prefixes.push(cur); k = 0; cur.clear(); } else if (c == ']') { int rep = counts.top(); counts.pop(); string prev = prefixes.top(); prefixes.pop(); while (rep--) prev += cur; cur = prev; } else { cur.push_back(c); } } return cur; }};import "strings"
func decodeString(s string) string { counts := []int{} prefixes := []string{} var cur strings.Builder k := 0 for i := 0; i < len(s); i++ { c := s[i] switch { case c >= '0' && c <= '9': k = k*10 + int(c-'0') case c == '[': counts = append(counts, k) prefixes = append(prefixes, cur.String()) k = 0 cur.Reset() case c == ']': rep := counts[len(counts)-1] counts = counts[:len(counts)-1] prev := prefixes[len(prefixes)-1] prefixes = prefixes[:len(prefixes)-1] inner := cur.String() cur.Reset() cur.WriteString(prev) for j := 0; j < rep; j++ { cur.WriteString(inner) } default: cur.WriteByte(c) } } return cur.String()}class Solution: def decodeString(self, s: str) -> str: counts: list[int] = [] prefixes: list[str] = [] cur = [] k = 0 for c in s: if c.isdigit(): k = k * 10 + int(c) elif c == '[': counts.append(k) prefixes.append(''.join(cur)) k = 0 cur = [] elif c == ']': rep = counts.pop() prev = prefixes.pop() inner = ''.join(cur) cur = [prev + inner * rep] else: cur.append(c) return ''.join(cur)function decodeString(s) { const counts = []; const prefixes = []; let cur = ''; let k = 0; for (const c of s) { if (c >= '0' && c <= '9') { k = k * 10 + (c.charCodeAt(0) - 48); } else if (c === '[') { counts.push(k); prefixes.push(cur); k = 0; cur = ''; } else if (c === ']') { const rep = counts.pop(); const prev = prefixes.pop(); cur = prev + cur.repeat(rep); } else { cur += c; } } return cur;}class Solution { public String decodeString(String s) { Deque<Integer> counts = new ArrayDeque<>(); Deque<StringBuilder> prefixes = new ArrayDeque<>(); StringBuilder cur = new StringBuilder(); int k = 0; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (Character.isDigit(c)) { k = k * 10 + (c - '0'); } else if (c == '[') { counts.push(k); prefixes.push(cur); k = 0; cur = new StringBuilder(); } else if (c == ']') { int rep = counts.pop(); StringBuilder prev = prefixes.pop(); for (int j = 0; j < rep; j++) prev.append(cur); cur = prev; } else { cur.append(c); } } return cur.toString(); }}function decodeString(s: string): string { const counts: number[] = []; const prefixes: string[] = []; let cur = ''; let k = 0; for (const c of s) { if (c >= '0' && c <= '9') { k = k * 10 + (c.charCodeAt(0) - 48); } else if (c === '[') { counts.push(k); prefixes.push(cur); k = 0; cur = ''; } else if (c === ']') { const rep = counts.pop() as number; const prev = prefixes.pop() as string; cur = prev + cur.repeat(rep); } else { cur += c; } } return cur;}Editorial#
The two-stack design keeps the half-built outer string safe while we focus on the inner sub-expression. Numbers can be multi-digit, so we accumulate k across digits. The total time is bounded by the length of the expanded output.
Complexity#
- Time: O(maxK * n).
- Space: O(n).
Concept revision#
Related#