Solve build ordering and expression evaluation
Company: Snowflake
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: Medium
Interview Round: Technical Screen
Quick Answer: This question evaluates competency in graph algorithms (topological ordering and cycle detection) and in parsing/evaluating arithmetic expressions with correct operator precedence, associativity, unary operators, and 64-bit integer semantics.
Dependency Ordering (Topological Sort)
Constraints
- 0 ≤ n ≤ 200000
- Each prereq pair is [a, b] with 0 ≤ a, b < n
- a requires b to be completed first (edge b -> a)
- Return [] if the graph has a cycle (no valid order exists)
- Any valid topological order is acceptable
Examples
Input: (2, [[1, 0]])
Expected Output: [0, 1]
Explanation: Task 1 requires task 0, so 0 must come before 1.
Input: (2, [[1, 0], [0, 1]])
Expected Output: []
Explanation: 0 and 1 depend on each other: a 2-node cycle, so no valid order exists.
Input: (0, [])
Expected Output: []
Explanation: No tasks; the (empty) order is returned as an empty array.
Input: (1, [])
Expected Output: [0]
Explanation: A single task with no prerequisites.
Input: (3, [])
Expected Output: [0, 1, 2]
Explanation: No prerequisites; all in-degree 0, emitted in ascending label order.
Input: (4, [[1, 0], [2, 0], [3, 1], [3, 2]])
Expected Output: [0, 1, 2, 3]
Explanation: Diamond DAG: 0 first, then 1 and 2, then 3 which depends on both.
Input: (3, [[0, 1], [1, 2], [2, 0]])
Expected Output: []
Explanation: A 3-node cycle 0->1->2->0 makes any ordering impossible.
Hints
- Build an adjacency list and an in-degree array. For pair [a, b], add edge b -> a and increment in-degree of a.
- Kahn's algorithm: start a queue with all tasks whose in-degree is 0, pop one at a time, append to the result, and decrement in-degrees of neighbors.
- If the final order's length is less than n, a cycle exists: return an empty array. Seeding/popping in ascending label order makes the output deterministic.
Arithmetic Expression Evaluator
Constraints
- Operands are non-negative integers in the source string; unary minus produces negatives
- Operators: + - * / % ^ ; plus parentheses and spaces
- Precedence: ^ (right-assoc) > unary minus > * / % (left-assoc) > + - (left-assoc)
- Division truncates toward zero; % is the matching remainder (sign of dividend)
- Use 64-bit signed integers; raise an error on malformed input
Examples
Input: ("1 + 2 * 3",)
Expected Output: 7
Explanation: * binds tighter than +, so 1 + 6 = 7.
Input: ("2 ^ 3 ^ 2",)
Expected Output: 512
Explanation: ^ is right-associative: 2 ^ (3 ^ 2) = 2 ^ 9 = 512.
Input: ("(1 + 2) * 3",)
Expected Output: 9
Explanation: Parentheses force the addition first: 3 * 3 = 9.
Input: ("-(3 + 4)",)
Expected Output: -7
Explanation: Unary minus applied to a parenthesized sub-expression.
Input: ("-2 ^ 2",)
Expected Output: -4
Explanation: ^ outranks unary minus, so this is -(2 ^ 2) = -4.
Input: ("7 / 2",)
Expected Output: 3
Explanation: Integer division truncates toward zero.
Input: ("-7 / 2",)
Expected Output: -3
Explanation: Truncate toward zero: -3 (not floor -4).
Input: ("7 % 3",)
Expected Output: 1
Explanation: Standard remainder.
Input: ("-7 % 3",)
Expected Output: -1
Explanation: Remainder takes the sign of the dividend: -7 - (-2)*3 = -1.
Input: ("10 - 2 - 3",)
Expected Output: 5
Explanation: Subtraction is left-associative: (10 - 2) - 3 = 5.
Input: ("2 * (3 + (4 - 1)) % 5",)
Expected Output: 2
Explanation: Nested parentheses: 2 * 6 = 12, then 12 % 5 = 2 (* and % are left-to-right).
Input: ("42",)
Expected Output: 42
Explanation: A bare integer evaluates to itself.
Input: ("- -5",)
Expected Output: 5
Explanation: Two stacked unary minuses cancel: -(-5) = 5.
Input: ("3 + -4 * 2",)
Expected Output: -5
Explanation: Unary minus before 4, then * binds before +: 3 + ((-4) * 2) = -5.
Hints
- Tokenize in one pass: collect digit runs into integer tokens and treat each operator/paren as its own token; reject any other character.
- A '-' is unary when it is the first token, follows another operator, or follows '('. Give unary minus precedence between ^ and the */% group.
- Use a shunting-yard loop with an operand stack and an operator stack. For ^ and unary minus (right-associative) pop only strictly-higher-precedence operators; for left-associative operators pop equal-or-higher. Implement truncate-toward-zero division and a matching remainder for %.