Implement stacks, streaming median, and upward path sum
Company: TikTok
Role: Data Scientist
Category: Coding & Algorithms
Difficulty: easy
Interview Round: Onsite
Quick Answer: This multi-part question evaluates proficiency in data structure design (augmented stacks for min/max, data structures for streaming medians), order-statistics and real-time aggregation, and constrained binary-tree traversal for upward-only paths, while requiring clear time/space complexity analysis and edge-case reasoning; such prompts are commonly asked to assess efficient state management, invariant maintenance, and algorithmic trade-off reasoning in the Coding & Algorithms domain. The level of abstraction spans practical implementation and conceptual understanding, emphasizing implementation-level details and complexity analysis for data-structure augmentation, streaming algorithms, and constrained tree traversal.
MinStack — Stack with O(1) getMin
Constraints
- operations[i] is one of 'push', 'pop', 'top', 'getMin'.
- values[i] is the integer argument for 'push' and an ignored placeholder otherwise.
- pop/top/getMin on an empty stack are tolerated and yield None.
- -10^9 <= pushed value <= 10^9.
Examples
Input: (['push','push','push','getMin','pop','top','getMin'], [-2,0,-3,0,0,0,0])
Expected Output: [None, None, None, -3, None, 0, -2]
Explanation: Push -2,0,-3. getMin -> -3. Pop -3. top -> 0. getMin -> -2.
Input: (['push','push','getMin','push','getMin','pop','getMin'], [5,5,0,3,0,0,0])
Expected Output: [None, None, 5, None, 3, None, 5]
Explanation: Duplicate minimums: getMin stays correct after popping one of the equal minima.
Input: (['getMin','top','pop'], [0,0,0])
Expected Output: [None, None, None]
Explanation: Edge case: all operations on an empty stack return None.
Input: (['push','getMin','top'], [42,0,0])
Expected Output: [None, 42, 42]
Explanation: Single element: it is both the min and the top.
Input: (['push','push','push','pop','pop','getMin','top'], [1,-1,-1,0,0,0,0])
Expected Output: [None, None, None, None, None, 1, 1]
Explanation: Push 1,-1,-1 then pop twice; remaining stack is [1] so min and top are 1.
Hints
- Keep a second stack that mirrors the main stack but stores the running minimum.
- On push, the new min-stack top is min(new value, previous min-stack top).
- Push and pop the two stacks together so they stay aligned; getMin is just min_stack[-1].
MaxStack — Stack with peekMax and popMax
Constraints
- operations[i] is one of 'push', 'pop', 'top', 'peekMax', 'popMax'.
- popMax removes the topmost occurrence when the maximum is duplicated.
- Operations on an empty stack yield None.
- -10^9 <= pushed value <= 10^9.
Examples
Input: (['push','push','push','top','popMax','top','peekMax','pop','top'], [5,1,5,0,0,0,0,0,0])
Expected Output: [None, None, None, 5, 5, 1, 5, 1, 5]
Explanation: Stack [5,1,5]: top 5; popMax removes the topmost 5 -> [5,1]; top 1; peekMax 5; pop 1 -> [5]; top 5.
Input: (['push','push','peekMax','popMax','peekMax'], [4,2,0,0,0])
Expected Output: [None, None, 4, 4, 2]
Explanation: peekMax 4, popMax removes 4 -> [2], peekMax 2.
Input: (['peekMax','popMax','pop','top'], [0,0,0,0])
Expected Output: [None, None, None, None]
Explanation: Edge case: every query on an empty stack returns None.
Input: (['push','peekMax','popMax','peekMax'], [7,0,0,0])
Expected Output: [None, 7, 7, None]
Explanation: Single element becomes the max; after popMax the stack is empty so peekMax is None.
Input: (['push','push','push','popMax','popMax','peekMax'], [-1,-3,-2,0,0,0])
Expected Output: [None, None, None, -1, -2, -3]
Explanation: All-negative values: popMax peels off -1 then -2, leaving -3 as the max.
Hints
- popMax must respect stack order on ties: scan from the top and remove the first element equal to the maximum.
- After removing a non-top element, the elements above it shift down by one position — the stack order is otherwise preserved.
- For O(log n), pair a balanced BST keyed by value (mapping to a stack of insertion ids) with the main stack, and delete lazily.
Streaming Median from a Data Stream
Constraints
- operations[i] is 'addNum' or 'findMedian'.
- values[i] is the integer for 'addNum' and an ignored placeholder for 'findMedian'.
- findMedian before any addNum returns None.
- Even count -> average of the two middle elements (a float).
Examples
Input: (['addNum','addNum','findMedian','addNum','findMedian'], [1,2,0,3,0])
Expected Output: [None, None, 1.5, None, 2.0]
Explanation: After 1,2 median is (1+2)/2=1.5; after adding 3 the sorted set is [1,2,3] so median is 2.0.
Input: (['findMedian'], [0])
Expected Output: [None]
Explanation: Edge case: querying before any number is added returns None.
Input: (['addNum','findMedian'], [5,0])
Expected Output: [None, 5.0]
Explanation: A single element is its own median (as a float).
Input: (['addNum','addNum','addNum','addNum','findMedian'], [-1,-2,-3,-4,0])
Expected Output: [None, None, None, None, -2.5]
Explanation: Negatives, even count: sorted [-4,-3,-2,-1], median (-3 + -2)/2 = -2.5.
Input: (['addNum','addNum','addNum','findMedian','addNum','addNum','findMedian'], [6,10,2,0,4,8,0])
Expected Output: [None, None, None, 6.0, None, None, 6.0]
Explanation: After 6,10,2 sorted [2,6,10] median 6.0; after 4,8 sorted [2,4,6,8,10] median 6.0.
Hints
- Split the data into a lower half (max-heap) and an upper half (min-heap).
- Always push to lo, immediately move lo's top to hi, then rebalance so lo holds the extra element on odd counts.
- Median is lo's top when sizes differ, else the average of both tops.
Binary Tree — Upward-Only Path Sum
Constraints
- tree is a level-order array; tree[i] is None for a missing node.
- The parent of node index i (>0) is (i - 1) // 2.
- An empty tree (or tree[0] is None) returns False.
- Node values and target may be negative.
- A path can be a single node (length-1 chain).
Examples
Input: ([5, 4, 8, 11, None, 13, 4, 7, 2], 22)
Expected Output: true
Explanation: Node 7 (index 7) -> 11 (index 3): 7 + 11 + 4 = 22 climbing up to node 4 (index 1).
Input: ([5, 4, 8, 11, None, 13, 4, 7, 2], 18)
Expected Output: true
Explanation: Node 7 -> its parent 11: 7 + 11 = 18.
Input: ([1, 2, 3], 100)
Expected Output: false
Explanation: No upward chain (3, 3+1, 2, 2+1, 1) reaches 100.
Input: ([], 0)
Expected Output: false
Explanation: Edge case: an empty tree has no path.
Input: ([10], 10)
Expected Output: true
Explanation: A single node is itself a length-1 upward path equal to the target.
Input: ([-2, None, -3], -5)
Expected Output: true
Explanation: Negative values: node -3 -> parent -2 gives -3 + -2 = -5.
Input: ([3, 9, 20, None, None, 15, 7], 23)
Expected Output: true
Explanation: Node 20 (index 2) -> root 3: 20 + 3 = 23.
Hints
- In the array layout you do not need real parent pointers: parent(i) = (i - 1) // 2.
- From each node, accumulate the sum while climbing to the root and check for an exact match at every step.
- Because values can be negative you cannot prune early on overshoot — examine every prefix of each upward chain.