Skip to content

Commit 9feb82a

Browse files
committed
feat(algorithms, stack): decode string)
1 parent af3d894 commit 9feb82a

File tree

4 files changed

+113
-23
lines changed

4 files changed

+113
-23
lines changed

algorithms/stack/decode_string/README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,53 @@ Output: "abcabccdcdcdef"
3232
- Stack
3333
- Recursion
3434

35+
## Solution
36+
37+
The essence of this approach lies in recognizing that the problem is naturally suited for a stack-based solution. When
38+
decoding a string, we need to handle nested and sequential patterns, and a stack allows us to manage these layers
39+
effectively. By pushing and popping elements on the stack as we encounter brackets, we can keep track of the substrings
40+
and their repeat counts. This method ensures we decode the string from the innermost nested structure outward,
41+
maintaining the correct order and repetition. To achieve this, we process each character in the string in the following
42+
way:
43+
44+
- **Digits**: Represent how many times a substring is repeated.
45+
- **Open bracket ([)**: Marks the start of a new substring and saves the current state by pushing the current substring
46+
and repeat count onto stacks and then resetting them for a new segment.
47+
- **Close bracket (])**: Ends the current substring, repeats it as specified, and appends it to the previous substring.
48+
- **Letters**: Build the current substring being processed.
49+
50+
This solution handles nested and consecutive encoding strings by utilizing the stack to track previously processed
51+
substrings and their associated repeat counts. The final decoded string is constructed by combining all parts accumulated
52+
in the stacks.
53+
54+
Here’s the step-by-step implementation of the solution:
55+
56+
- Initialize two empty stacks: count_stack for storing repeat counts and string_stack for storing intermediate strings.
57+
- Initialize current as an empty string. This will hold the currently decoded string segment.
58+
- Initialize k as 0: This will store multi-digit numbers representing repeat counts.
59+
- Iterate through each character char in the input string s:
60+
- If char is a digit:
61+
- Update k to accumulate the digit into a multi-digit number by performing k = 10 * k + int(char).
62+
- If char is a '[':
63+
- Push k onto count_stack to save the current repeat count.
64+
- Push current onto string_stack to save the current string segment.
65+
- Reset k to 0 for the next repeat count.
66+
- Reset current to an empty string to start decoding the new segment.
67+
- If char is a’]’:
68+
- Pop the last string segment from string_stack and store it in decoded_string.
69+
- Pop the last repeat count from count_stack and store it in num.
70+
- Update current by appending current * num to decoded_string, repeating the decoded segment, and combining it with
71+
the previous string.
72+
- If char is a regular character:
73+
- Append char to current, adding it to the currently decoded string segment.
74+
- After processing all characters, current will contain the fully decoded string.
75+
76+
### Time Complexity
77+
78+
The time complexity of this solution is O(n∗m∗k), where n is the length of the input string, m is the length of current,
79+
and k is the maximum multiplier encountered during the decoding.
80+
81+
### Space Complexity
82+
83+
The space complexity of this solution is O(c+d), where c is the number of alphabets and d is the number of digits in the
84+
input string.

algorithms/stack/decode_string/__init__.py

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,61 @@ def decode_string(s: str) -> str:
22
stack, result, num = [], "", 0
33

44
for char in s:
5+
# If the character is a digit, update num to accumulate the multi-digit number
56
if char.isdigit():
67
num = num * 10 + int(char)
78
elif char == "[":
9+
# When encountering '[', push num and result onto the stack
810
stack.append(result)
911
stack.append(num)
12+
# Reset num and result for the new segment inside the brackets
1013
result = ""
1114
num = 0
1215
elif char == "]":
13-
p_num = stack.pop()
14-
p_str = stack.pop()
15-
result = p_str + p_num * result
16+
# When encountering ']', pop the last string and count from the stack
17+
popped_num = stack.pop()
18+
popped_str = stack.pop()
19+
# Repeat the result string popped_num times and append it to the popped string
20+
result = popped_str + popped_num * result
1621
else:
22+
# For regular characters, append them to the result string
1723
result += char
1824

25+
# Return the fully decoded string after processing all characters
1926
return result
27+
28+
29+
def decode_string_2(s: str) -> str:
30+
# Initialize two stacks: one for numbers (repeat counts) and one for strings
31+
count_stack = []
32+
string_stack = []
33+
34+
# Initialize an empty string to hold the current decoded segment
35+
current = ""
36+
# Initialize k to accumulate multi-digit numbers for repeat counts
37+
k = 0
38+
39+
# Loop through each character in the input string s
40+
for char in s:
41+
if char.isdigit():
42+
# If the character is a digit, update k to accumulate the multi-digit number
43+
k = 10 * k + int(char)
44+
elif char == "[":
45+
# When encountering '[', push k onto the count stack and current onto the string stack
46+
count_stack.append(k)
47+
string_stack.append(current)
48+
# Reset k and current for the new segment inside the brackets
49+
k = 0
50+
current = ""
51+
elif char == "]":
52+
# When encountering ']', pop the last string and count from the stacks
53+
popped_string = string_stack.pop()
54+
num = count_stack.pop()
55+
# Repeat the current string num times and append it to the popped string
56+
current = popped_string + current * num
57+
else:
58+
# For regular characters, append them to the current string
59+
current += char
60+
61+
# Return the fully decoded string after processing all characters
62+
return current

algorithms/stack/decode_string/test_decode_string.py

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,25 @@
11
import unittest
2+
from parameterized import parameterized
3+
from algorithms.stack.decode_string import decode_string, decode_string_2
24

3-
from . import decode_string
5+
DECODE_STRING_TEST_CASES = [
6+
("3[a]2[bc]", "aaabcbc"),
7+
("3[a2[c]]", "accaccacc"),
8+
("2[abc]3[cd]ef", "abcabccdcdcdef"),
9+
("1[abc]2[def]3[ghi]", "abcdefdefghighighi"),
10+
("1[a2[b3[c4[d]]]]", "abcddddcddddcddddbcddddcddddcdddd"),
11+
]
412

513

614
class DecodeStringTestCases(unittest.TestCase):
7-
def test_one(self):
8-
"""should return aaabcbc from 3[a]2[bc]"""
9-
encoded_string = "3[a]2[bc]"
10-
expected = "aaabcbc"
15+
@parameterized.expand(DECODE_STRING_TEST_CASES)
16+
def test_decode_string(self, encoded_string: str, expected: str):
1117
actual = decode_string(encoded_string)
1218
self.assertEqual(expected, actual)
1319

14-
def test_two(self):
15-
"""should return aaabcbc from 3[a2[c]]"""
16-
encoded_string = "3[a2[c]]"
17-
expected = "accaccacc"
18-
actual = decode_string(encoded_string)
19-
self.assertEqual(expected, actual)
20-
21-
def test_three(self):
22-
"""should return abcabccdcdcdef from 2[abc]3[cd]ef"""
23-
encoded_string = "2[abc]3[cd]ef"
24-
expected = "abcabccdcdcdef"
25-
actual = decode_string(encoded_string)
20+
@parameterized.expand(DECODE_STRING_TEST_CASES)
21+
def test_decode_string_2(self, encoded_string: str, expected: str):
22+
actual = decode_string_2(encoded_string)
2623
self.assertEqual(expected, actual)
2724

2825

algorithms/stack/reverse_string/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ def reverse_string(text: str) -> str:
3636
def reverse_string_char_array(s: List[str]) -> None:
3737
"""
3838
Reverses a character array in place using two-pointer technique.
39-
39+
4040
Reference: https://leetcode.com/problems/reverse-string/
41-
41+
4242
Complexity:
4343
Where n is the length of the input list
4444
Time: O(n), each character is visited at most once
4545
Space: O(1), only two pointers used, no extra data structures
46-
46+
4747
Args:
4848
s (List[str]): character array to reverse in place
4949
Returns:

0 commit comments

Comments
 (0)