Implement stack and interval algorithms with tests
Company: Rippling
Role: Machine Learning Engineer
Category: Coding & Algorithms
Difficulty: Medium
Interview Round: Onsite
Quick Answer: This question evaluates implementation-level competencies with fundamental data structures and algorithms—stack-based bracket validation, interval merging with open/closed endpoint semantics, and arithmetic expression evaluation using stacks—while also measuring the ability to design comprehensive unit tests; category: Coding & Algorithms for a Machine Learning Engineer role. It is commonly asked to gauge practical coding ability, correctness under tricky edge cases and input semantics, and test-coverage awareness, representing a practical application-level assessment that also requires conceptual reasoning about invariants and boundary behavior.
Part 1: Validate Bracket String with a Stack
Constraints
- 0 <= len(s) <= 100000
- s contains only '(', ')', '[', ']', '{', '}'
- Target complexity: O(n) time and O(n) auxiliary space
- Do not modify the input string
Examples
Input: "()[]{}"
Expected Output: True
Explanation: All brackets are matched and appear in valid order.
Input: "([{}])"
Expected Output: True
Explanation: This is a properly nested bracket string.
Input: "([)]"
Expected Output: False
Explanation: The bracket types cross, so nesting is invalid.
Input: "]{"
Expected Output: False
Explanation: The string starts with a closing bracket, so it cannot be valid.
Input: ""
Expected Output: True
Explanation: An empty string has no mismatched brackets.
Hints
- Use a stack to store opening brackets as you scan from left to right.
- When you see a closing bracket, the top of the stack must be the matching opening bracket.
Part 2: Merge Intervals with Open/Closed Endpoints
Constraints
- 0 <= number of intervals <= 200000
- For every interval, start <= end
- If start == end and not both endpoints are closed, the interval is empty
- Target complexity: O(n log n) time due to sorting and O(n) extra space
Examples
Input: [(1, 3, True, True), (3, 5, True, False)]
Expected Output: [(1, 5, True, False)]
Explanation: [1,3] and [3,5) touch at 3, and at least one touching endpoint is closed, so they merge.
Input: [(1, 3, True, False), (3, 5, False, True)]
Expected Output: [(1, 3, True, False), (3, 5, False, True)]
Explanation: [1,3) and (3,5] do not overlap and do not merge because neither interval includes 3.
Input: [(1, 4, True, False), (2, 4, False, True)]
Expected Output: [(1, 4, True, True)]
Explanation: The intervals overlap, and the merged interval keeps the shared end 4 as closed because one interval includes it.
Input: []
Expected Output: []
Explanation: An empty input list produces an empty union.
Input: [(3, 3, False, False), (3, 3, True, True), (3, 3, True, True), (5, 7, False, True), (1, 2, True, False), (2, 5, True, False)]
Expected Output: [(1, 5, True, False), (5, 7, False, True)]
Explanation: The empty interval (3,3) is discarded, duplicates are absorbed, [1,2) merges with [2,5), and (5,7] remains separate because 5 is excluded from both sides.
Hints
- Sort intervals by starting position, with closed left endpoints before open ones when starts are equal.
- When two merged intervals end at the same value, the merged right endpoint is closed if either interval includes that endpoint.
Part 3: Evaluate Arithmetic Expression Using Stacks
Constraints
- 1 <= len(expr) <= 100000
- expr contains digits, spaces, '+', '-', '*', '/', and parentheses
- The expression is valid
- Intermediate and final results fit in 32-bit signed integer range
- Target complexity: O(n) time and O(n) space
Examples
Input: "1 + 2 * 3"
Expected Output: 7
Explanation: Multiplication happens before addition.
Input: "((42))"
Expected Output: 42
Explanation: Nested parentheses around a single number should still evaluate correctly.
Input: "-3+5"
Expected Output: 2
Explanation: The leading minus is unary, so the expression is (-3) + 5.
Input: "1+-2"
Expected Output: -1
Explanation: The second minus is unary, so the expression is 1 + (-2).
Input: "2*(-3 + 4) + 7 / 2"
Expected Output: 5
Explanation: (-3 + 4) = 1, so 2*1 = 2, and 7/2 truncates toward zero to 3, giving 2 + 3 = 5.
Hints
- Use one stack for numbers and one for operators, applying operators by precedence.
- Treat unary minus as a separate operator with higher precedence than binary + and -.