title: Basic Calculator
slug: basic-calculator
difficulty: hard
leetcode_id: 224
leetcode_url: https://leetcode.com/problems/basic-calculator/
categories:
  - strings
  - stack
  - math
patterns:
  - monotonic-stack

function_signature: "def calculate(s: str) -> int:"

test_cases:
  visible:
    - input: { s: "1 + 1" }
      expected: 2
    - input: { s: " 2-1 + 2 " }
      expected: 3
    - input: { s: "(1+(4+5+2)-3)+(6+8)" }
      expected: 23
  hidden:
    - input: { s: "1" }
      expected: 1
    - input: { s: "-1" }
      expected: -1
    - input: { s: "-(3+2)" }
      expected: -5
    - input: { s: "1-(5)" }
      expected: -4
    - input: { s: "2147483647" }
      expected: 2147483647
    - input: { s: "1-(-2)" }
      expected: 3

description: |
  Given a string `s` representing a valid expression, implement a basic calculator to evaluate it, and return *the result of the evaluation*.

  **Note:** You are **not** allowed to use any built-in function which evaluates strings as mathematical expressions, such as `eval()`.

constraints: |
  - `1 <= s.length <= 3 * 10^5`
  - `s` consists of digits, `'+'`, `'-'`, `'('`, `')'`, and `' '`
  - `s` represents a valid expression
  - `'+'` is **not** used as a unary operation (i.e., `"+1"` and `"+(2 + 3)"` is invalid)
  - `'-'` could be used as a unary operation (i.e., `"-1"` and `"-(2 + 3)"` is valid)
  - There will be no two consecutive operators in the input
  - Every number and running calculation will fit in a signed 32-bit integer

examples:
  - input: 's = "1 + 1"'
    output: "2"
    explanation: "Simple addition of two numbers."
  - input: 's = " 2-1 + 2 "'
    output: "3"
    explanation: "2 - 1 = 1, then 1 + 2 = 3. Spaces are ignored."
  - input: 's = "(1+(4+5+2)-3)+(6+8)"'
    output: "23"
    explanation: "Inner parentheses: (4+5+2) = 11, so (1+11-3) = 9. Then (6+8) = 14. Finally 9 + 14 = 23."

explanation:
  intuition: |
    Imagine you're evaluating a mathematical expression by hand. When you encounter parentheses, you mentally "pause" what you were doing, compute the inner expression first, and then come back to where you left off.

    This is exactly what a **stack** enables programmatically. Think of the stack as a "memory" for the outer context. When you see an opening parenthesis `(`, you save your current progress (the running result and the sign before the parenthesis) onto the stack. Then you start fresh to compute the inner expression. When you hit a closing parenthesis `)`, you pop the saved context and combine it with the inner result.

    The key insight is that addition and subtraction are **left-associative** and have the **same precedence**, so we can evaluate the expression in a single left-to-right pass. The only complication is parentheses, which create nested scopes that we handle with a stack.

    For the sign, we track whether the next number should be added or subtracted. A `+` means add (sign = 1), and a `-` means subtract (sign = -1). Unary minus (like `-5` or `-(3+2)`) is handled naturally by setting the sign before parsing the number or entering the parentheses.

  approach: |
    We solve this using a **Stack-Based Single Pass** approach:

    **Step 1: Initialise variables**

    - `result`: Set to `0` to accumulate the running total
    - `sign`: Set to `1` (positive) representing whether to add or subtract the next value
    - `stack`: Empty list to save context when entering parentheses
    - `i`: Index to iterate through the string

    &nbsp;

    **Step 2: Iterate through each character**

    - **Digit**: Build the full number (could be multi-digit), then add `sign * number` to result
    - **`+`**: Set sign to `1` (next value will be added)
    - **`-`**: Set sign to `-1` (next value will be subtracted)
    - **`(`**: Push current `result` and `sign` onto stack, then reset `result = 0` and `sign = 1` to start evaluating the sub-expression
    - **`)`**: Pop the saved sign and previous result from the stack. Compute `popped_result + popped_sign * result` to combine inner result with outer context
    - **Space**: Skip whitespace characters

    &nbsp;

    **Step 3: Return the result**

    - After processing all characters, `result` contains the final evaluated value

    &nbsp;

    The stack stores pairs of `(previous_result, sign_before_parenthesis)`. This lets us "freeze" the outer computation, evaluate the inner expression independently, and then seamlessly merge them when we close the parenthesis.

  common_pitfalls:
    - title: Not Handling Multi-Digit Numbers
      description: |
        A common mistake is treating each digit character as a separate number. For example, `"123"` should be parsed as the number `123`, not `1`, `2`, `3`.

        You need a loop that continues reading digits while the current character is a digit, building the number: `num = num * 10 + int(char)`.
      wrong_approach: "Treating each digit as a separate number"
      correct_approach: "Build multi-digit numbers in a loop"

    - title: Forgetting Unary Minus
      description: |
        The problem states that `-` can be used as a unary operator, like `-1` or `-(3+2)`. If you only handle binary subtraction, expressions like `"-(1+2)"` will fail.

        The sign variable naturally handles this: when we see `-` followed by `(`, we push the current state with sign `-1`, so the entire inner result gets negated.
      wrong_approach: "Only handling binary subtraction"
      correct_approach: "Track sign separately; it applies to both numbers and sub-expressions"

    - title: Incorrect Stack Order
      description: |
        When pushing to and popping from the stack, order matters. You need to push `result` first, then `sign`, and pop in reverse order (sign first, then result).

        If you get this backwards, you'll apply the wrong sign or add to the wrong accumulated value.
      wrong_approach: "Inconsistent push/pop order"
      correct_approach: "Push (result, sign) in order; pop sign first, then result"

    - title: Not Resetting After Opening Parenthesis
      description: |
        After pushing the current context onto the stack, you must reset `result = 0` and `sign = 1` to start evaluating the inner expression from scratch.

        Forgetting to reset means you'll incorrectly mix the outer and inner computations.
      wrong_approach: "Continuing with old result/sign after '('"
      correct_approach: "Reset result = 0 and sign = 1 after pushing to stack"

  key_takeaways:
    - "**Stack for nested structures**: Stacks are ideal for problems involving parentheses or any nested scope. Push context on open, pop on close."
    - "**Sign tracking**: Instead of handling `+` and `-` as operators between terms, track a sign multiplier that applies to the next value."
    - "**Single pass efficiency**: Despite the apparent complexity, expression evaluation with `+`, `-`, and parentheses can be done in O(n) time."
    - "**Foundation for harder calculators**: This pattern extends to Basic Calculator II (with `*` and `/`) and III (with all operators and parentheses)."

  time_complexity: "O(n). We iterate through each character in the string exactly once."
  space_complexity: "O(n). In the worst case with deeply nested parentheses like `(((...)))`, the stack stores O(n) pairs."

solutions:
  - approach_name: Stack-Based Single Pass
    is_optimal: true
    code: |
      def calculate(s: str) -> int:
          result = 0      # Running total for current scope
          sign = 1        # 1 for positive, -1 for negative
          stack = []      # Stores (result, sign) when entering parentheses
          i = 0
          n = len(s)

          while i < n:
              char = s[i]

              if char.isdigit():
                  # Build the full number (could be multi-digit)
                  num = 0
                  while i < n and s[i].isdigit():
                      num = num * 10 + int(s[i])
                      i += 1
                  # Add (or subtract) this number to our result
                  result += sign * num
                  continue  # i already advanced past the number

              elif char == '+':
                  # Next number should be added
                  sign = 1

              elif char == '-':
                  # Next number should be subtracted
                  sign = -1

              elif char == '(':
                  # Save current context and start fresh
                  stack.append(result)
                  stack.append(sign)
                  result = 0
                  sign = 1

              elif char == ')':
                  # Combine inner result with saved outer context
                  prev_sign = stack.pop()
                  prev_result = stack.pop()
                  result = prev_result + prev_sign * result

              # Skip spaces (char == ' ')
              i += 1

          return result
    explanation: |
      **Time Complexity:** O(n) — Single pass through the string.

      **Space Complexity:** O(n) — Stack depth proportional to nesting level, worst case O(n).

      We process each character once. Digits form multi-digit numbers, operators update the sign, and parentheses push/pop context from the stack. The sign variable elegantly handles both binary subtraction and unary minus.

  - approach_name: Recursive Descent
    is_optimal: false
    code: |
      def calculate(s: str) -> int:
          # Remove all spaces for easier parsing
          s = s.replace(' ', '')
          index = [0]  # Use list for mutable reference in nested function

          def parse_expression() -> int:
              result = 0
              sign = 1

              while index[0] < len(s):
                  char = s[index[0]]

                  if char.isdigit():
                      # Parse multi-digit number
                      num = 0
                      while index[0] < len(s) and s[index[0]].isdigit():
                          num = num * 10 + int(s[index[0]])
                          index[0] += 1
                      result += sign * num
                      continue

                  elif char == '+':
                      sign = 1
                      index[0] += 1

                  elif char == '-':
                      sign = -1
                      index[0] += 1

                  elif char == '(':
                      index[0] += 1  # Skip '('
                      # Recursively evaluate sub-expression
                      inner = parse_expression()
                      result += sign * inner

                  elif char == ')':
                      index[0] += 1  # Skip ')'
                      return result  # Return to caller

                  else:
                      index[0] += 1  # Skip unexpected characters

              return result

          return parse_expression()
    explanation: |
      **Time Complexity:** O(n) — Each character is visited once.

      **Space Complexity:** O(n) — Recursion depth proportional to nesting level.

      This approach uses recursion to handle parentheses. When we see `(`, we recursively call `parse_expression()` to evaluate the inner content. When we see `)`, we return the inner result to the caller. The recursion stack implicitly does what the explicit stack does in the iterative solution.

      While equally efficient, this approach may hit Python's recursion limit for very deeply nested expressions, making the iterative stack solution preferred.
