Solve Linked-List and Iterator Problems
Company: Airbnb
Role: Software Engineer
Category: Coding & Algorithms
Interview Round: Onsite
Quick Answer: This question evaluates proficiency in linked-list pointer reasoning, cycle detection and shared-reference identification, as well as iterator design for round-robin merging, testing data-structure manipulation, iterator interfaces, and complexity analysis within the Coding & Algorithms domain.
Part 1: Determine Whether Two Possibly Cyclic Linked Lists Share Any Node
Constraints
- 0 <= len(next_index) <= 200000
- -1 <= head_a, head_b < len(next_index), unless len(next_index) is 0, in which case both heads must be -1
- For every i, next_index[i] is either -1 or an integer in the range [0, len(next_index) - 1]
- Each node has at most one outgoing edge, so each head defines a singly linked list that may contain a cycle
Examples
Input: ([1, 2, 3, -1, 5, 6, 3], 0, 4)
Expected Output: True
Explanation: List A is 0->1->2->3. List B is 4->5->6->3. They meet at node 3.
Input: ([1, 2, 0, 4, 5, 3], 0, 3)
Expected Output: False
Explanation: The lists are two separate cycles: 0->1->2->0 and 3->4->5->3.
Input: ([1, 2, 3, 4, 2, 6, 4], 0, 5)
Expected Output: True
Explanation: Both lists eventually enter the same cycle, but one enters at node 2 and the other at node 4.
Input: ([], -1, -1)
Expected Output: False
Explanation: Two empty lists share no node.
Input: ([1, 2, 1, 4, -1], 0, 3)
Expected Output: False
Explanation: One list is cyclic and the other is acyclic, and they never touch.
Hints
- If you record every distinct node reachable from one head, the second traversal becomes a membership check.
- Because cycles are possible, stop traversing a list when you revisit a node.
Part 2: Return a Shared Node in Two Possibly Cyclic Linked Lists
Constraints
- 0 <= len(next_index) <= 200000
- -1 <= head_a, head_b < len(next_index), unless len(next_index) is 0, in which case both heads must be -1
- For every i, next_index[i] is either -1 or an integer in the range [0, len(next_index) - 1]
- Each node has at most one outgoing edge, so each head defines a singly linked list that may contain a cycle
Examples
Input: ([1, 2, 3, -1, 5, 6, 3], 0, 4)
Expected Output: 3
Explanation: The two lists first meet at node 3.
Input: ([1, 2, 0, 4, 5, 3], 0, 3)
Expected Output: -1
Explanation: The two cycles are completely separate.
Input: ([1, 2, 3, 4, 2, 6, 4], 0, 5)
Expected Output: 4
Explanation: Both lists share the same cycle. The reference solution returns the first shared node seen while traversing list B, which is 4.
Input: ([0], 0, 0)
Expected Output: 0
Explanation: Both heads already point to the same single-node cycle.
Input: ([1, -1], 0, -1)
Expected Output: -1
Explanation: An empty second list cannot share a node.
Hints
- Store all distinct nodes reachable from the first head, then walk the second list until you either hit one of them or stop.
- To avoid infinite loops in cyclic lists, remember which nodes you have already visited during each traversal.
Part 3: Simulate a Round-Robin Multi-Stream Iterator
Constraints
- 0 <= len(streams) <= 100000
- 0 <= sum(len(stream) for stream in streams) <= 200000
- 0 <= len(operations) <= 200000
- Each stream element is a single-character string
- Every operation is either 'has_next' or 'next'
Examples
Input: ([['A', 'B', 'C'], ['x', 'y'], ['1', '2', '3', '4']], ['has_next', 'next', 'next', 'next', 'next', 'next', 'next', 'next', 'next', 'next', 'has_next'])
Expected Output: ['true', 'A', 'x', '1', 'B', 'y', '2', 'C', '3', '4', 'false']
Explanation: The iterator alternates among non-empty streams and skips exhausted ones.
Input: ([], ['has_next', 'next'])
Expected Output: ['false', 'EXCEPTION']
Explanation: With no streams, nothing can be read.
Input: ([[], ['a'], [], ['b', 'c']], ['has_next', 'has_next', 'next', 'has_next', 'next', 'next', 'has_next', 'next'])
Expected Output: ['true', 'true', 'a', 'true', 'b', 'c', 'false', 'EXCEPTION']
Explanation: Empty streams are ignored, and repeated 'has_next' calls do not consume anything.
Input: ([['z']], ['next', 'has_next', 'next'])
Expected Output: ['z', 'false', 'EXCEPTION']
Explanation: After reading the only character, the iterator is exhausted.
Hints
- Keep a queue of the stream indices that still have remaining characters.
- Store the current read position for each stream so that 'has_next' can stay O(1) and never consumes data.