Evaluate arithmetic expression using DFS
Company: Instacart
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: Medium
Interview Round: HR Screen
Quick Answer: This question evaluates a candidate's understanding of expression parsing and evaluation using depth-first traversal, covering competencies in recursive descent or stack-based DFS, operator precedence, unary operators, and 64-bit integer division semantics with truncation toward zero.
Constraints
- The expression contains only digits, '+', '-', '*', '/', '(', ')', and spaces.
- All integer literals are non-negative; negative values arise only from unary minus.
- The expression is well-formed (balanced parentheses, no division by zero).
- Division truncates toward zero, not toward negative infinity.
- The result fits in a 64-bit signed integer.
Examples
Input: "1 + 2 * 3"
Expected Output: 7
Explanation: Multiplication binds tighter than addition: 2*3=6, then 1+6=7.
Input: "(1 + 2) * 3"
Expected Output: 9
Explanation: Parentheses force the addition first: (1+2)=3, then 3*3=9.
Input: "10 - 2 - 3"
Expected Output: 5
Explanation: Subtraction is left-associative: (10-2)-3 = 8-3 = 5.
Input: "2 * 3 + 4 * 5"
Expected Output: 26
Explanation: Each product is evaluated before the sum: 6 + 20 = 26.
Input: "-3 + 5"
Expected Output: 2
Explanation: Leading unary minus produces -3, then -3+5 = 2.
Input: "-(3 + 4)"
Expected Output: -7
Explanation: Unary minus applied to a parenthesized subexpression: -(7) = -7.
Input: "7 / 2"
Expected Output: 3
Explanation: Integer division truncates toward zero: 7/2 = 3.
Input: "-7 / 2"
Expected Output: -3
Explanation: Truncation toward zero, not floor: -7/2 = -3 (floor would give -4).
Input: "3 + 5 / 2"
Expected Output: 5
Explanation: 5/2 truncates to 2, then 3+2 = 5.
Input: "2 * (3 + (4 - 1))"
Expected Output: 12
Explanation: Nested parentheses: (4-1)=3, (3+3)=6, 2*6 = 12.
Input: "42"
Expected Output: 42
Explanation: A bare integer evaluates to itself.
Input: " 10 + 20 "
Expected Output: 30
Explanation: Leading, trailing, and interior spaces are ignored: 10+20 = 30.
Input: "10 / 3 * 3"
Expected Output: 9
Explanation: Left-to-right within the same precedence: (10/3)=3 then 3*3 = 9, showing intermediate truncation.
Hints
- Define three mutually recursive parse functions following the grammar: parse_expr handles + and -, parse_term handles * and /, and parse_factor handles unary signs, parentheses, and integer literals. This naturally encodes precedence.
- Maintain a single shared cursor index into the string (e.g. a one-element list in Python or a class field) so all parse functions advance the same position. Skip spaces before reading each token.
- For truncate-toward-zero division, compute abs(a)//abs(b) and negate the quotient when exactly one operand is negative — Python's // floors, which differs for negatives (e.g. -7//2 == -4 but truncation gives -3).
- Recursion depth equals the maximum parenthesis nesting; for adversarial inputs convert to an iterative two-stack algorithm (values + operators) and pop/apply whenever the incoming operator has lower-or-equal precedence.