{x}
blog image

Mini Parser

Given a string s represents the serialization of a nested list, implement a parser to deserialize it and return the deserialized NestedInteger.

Each element is either an integer or a list whose elements may also be integers or other lists.

 

Example 1:

Input: s = "324"
Output: 324
Explanation: You should return a NestedInteger object which contains a single integer 324.

Example 2:

Input: s = "[123,[456,[789]]]"
Output: [123,[456,[789]]]
Explanation: Return a NestedInteger object containing a nested list with 2 elements:
1. An integer containing value 123.
2. A nested list containing two elements:
    i.  An integer containing value 456.
    ii. A nested list with one element:
         a. An integer containing value 789

 

Constraints:

  • 1 <= s.length <= 5 * 104
  • s consists of digits, square brackets "[]", negative sign '-', and commas ','.
  • s is the serialization of valid NestedInteger.
  • All the values in the input are in the range [-106, 106].

Solution Explanation for Mini Parser

This problem involves deserializing a string representing a nested list into a nested integer structure. Two approaches are presented: recursion and stack-based iteration. Both achieve a time complexity of O(n), where n is the length of the input string.

Approach 1: Recursion

This approach leverages recursion to elegantly handle the nested structure. The core idea is to break down the problem into smaller subproblems.

Algorithm:

  1. Base Cases:

    • If the input string s is empty or represents an empty list ([]), return an empty NestedInteger.
    • If s starts with a digit (not a '['), it represents a single integer; parse it and return a NestedInteger containing that integer.
  2. Recursive Step:

    • For nested lists, the string will be enclosed in square brackets ([...]). The algorithm iterates through the string:
      • When a comma (,) or the closing bracket (]) is encountered while the depth is 0, it indicates the end of a NestedInteger within the current list. A substring is extracted, representing this inner element, and the function recursively calls itself (deserialize()) to parse this substring. The resulting NestedInteger is added to the current list.
      • Opening brackets ([) increment the depth, and closing brackets (]) decrement it. This tracks the nesting levels.

Time Complexity: O(n) - Each character is visited at most once during traversal and recursion.

Space Complexity: O(n) - The recursive call stack can have a depth proportional to the nesting level, and the nested list structure itself can also take O(n) space.

Approach 2: Stack

This approach uses a stack data structure to mimic the recursion process iteratively.

Algorithm:

  1. Base Case: If the input string s does not start with '[', it's a single integer; parse and return.

  2. Iteration and Stack Management: The algorithm iterates through the input string:

    • '-': Sets a neg flag to handle negative numbers.
    • Digit: Accumulates digits into the x variable.
    • '[': Pushes a new NestedInteger onto the stack to represent a new nested list.
    • ',' or ']: If the previous character was a digit, it means a number is complete. The accumulated number x (considering the neg flag) is added to the top NestedInteger on the stack. If it's ']', and the stack has more than one element, the top NestedInteger is popped and added to the one below it, reflecting the nested structure.

Time Complexity: O(n) - Similar to the recursive approach, each character is processed once.

Space Complexity: O(n) - The stack can grow to a size proportional to the maximum nesting depth of the list.

Code Examples (Python)

Approach 1 (Recursion):

class Solution:
    def deserialize(self, s: str) -> NestedInteger:
        if not s or s == '[]':
            return NestedInteger()
        if s[0] != '[':
            return NestedInteger(int(s))
        ans = NestedInteger()
        depth, j = 0, 1
        for i in range(1, len(s)):
            if depth == 0 and (s[i] == ',' or i == len(s) - 1):
                ans.add(self.deserialize(s[j:i]))
                j = i + 1
            elif s[i] == '[':
                depth += 1
            elif s[i] == ']':
                depth -= 1
        return ans

Approach 2 (Stack):

class Solution:
    def deserialize(self, s: str) -> NestedInteger:
        if s[0] != '[':
            return NestedInteger(int(s))
        stk, x, neg = [], 0, False
        for i, c in enumerate(s):
            if c == '-':
                neg = True
            elif c.isdigit():
                x = x * 10 + int(c)
            elif c == '[':
                stk.append(NestedInteger())
            elif c in ',]':
                if s[i - 1].isdigit():
                    if neg:
                        x = -x
                    stk[-1].add(NestedInteger(x))
                x, neg = 0, False
                if c == ']' and len(stk) > 1:
                    t = stk.pop()
                    stk[-1].add(t)
        return stk.pop()

The code examples in other languages (Java, C++, Go, TypeScript) would follow similar algorithmic structures, adapting syntax and data structures as needed for each language. The core concepts of recursion or stack-based iteration remain the same across all implementations.