Evaluate a Variadic Addition or Subtraction Expression
AndurilSoftware Engineer · OnsiteLast updated
Implement a variadic prefix expression evaluator supporting addition and left-associative subtraction with support for nested expressions and error handling.
Problem Statement
Implement an evaluator for prefix-style variadic expressions. An expression is represented either as a single integer or as a list where the first element is an operator string ("+" or "-") and all subsequent elements are operands. Operands can be integers or nested expressions.
The operators behave as follows:
"+": Computes the sum of all evaluated operands. If no operands are provided (["+"]), the result is0."-": If given a single operand, it computes the negation (-operand). If given two or more operands, it subtracts all subsequent evaluated operands from the first in left-associative order (e.g.,["-", a, b, c]evaluates to(a - b) - c). If given zero operands (["-"]), it should raise aValueError.
Your implementation should validate the input and raise a ValueError if:
- An expression list is empty.
- The first element of an expression list is not a supported operator.
- Any operand is neither an integer nor a valid expression list.
Function Signature
def evaluate(expr: int | list) -> int:
pass
Examples
Example 1:
expr = ["+", 1, 2, 3, 4]
# Output: 10
# Explanation: 1 + 2 + 3 + 4 = 10
Example 2:
expr = ["-", 10, 2, 3]
# Output: 5
# Explanation: (10 - 2) - 3 = 5
Example 3:
expr = ["-", ["+", 5, 5], ["-", 3]]
# Output: 13
# Explanation:
# ["+", 5, 5] evaluates to 10.
# ["-", 3] is unary negation, evaluating to -3.
# ["-", 10, -3] evaluates to 10 - (-3) = 13.
Constraints
- The total number of elements across all nested lists is at most
10^5. - Integers are standard 32-bit signed integers.
- Maximum nesting depth is at most
1000. - Time complexity must be
O(N)whereNis the total number of tokens/elements. - Auxiliary space complexity must be
O(D)whereDis the maximum nesting depth.
Hints
Hint 1
Use recursion where the base case handles integer inputs directly and the recursive step processes operator lists by first evaluating each operand.
Hint 2
Structure operator behavior using an extensible dispatch dictionary or handler functions mapping '"+"' and '"-"' to their respective accumulator logic.
Hint 3
Ensure the subtraction handler explicitly distinguishes between zero operands (error), one operand (unary negation), and multiple operands (left-associative reduction).
Follow-up questions
- How would you refactor your design to easily register new variadic operators like `"*"`, `"/"`, or `"max"` without modifying core traversal logic?
- If the nesting depth exceeds typical recursion limits (e.g., `> 10^5`), how would you rewrite the evaluator iteratively?
- How would you adapt the evaluator to support lazy evaluation or short-circuiting if boolean operators like `"AND"` or `"OR"` were introduced?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.