Implement array merge, round-robin scheduler, and trading simulator
Company: Citadel
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Onsite
Quick Answer: This multipart problem evaluates algorithmic problem solving and systems-design competencies including in-place array manipulation, queue-based scheduling, and event-driven trading simulation, while testing API/interface specification, edge-case handling, and time/space complexity analysis.
Part 1: Merge Two Sorted Arrays In-Place
Constraints
- 0 <= m, n <= 200000
- len(nums1) == m + n
- len(nums2) == n
- Values fit in a 32-bit signed integer
- The first m elements of nums1 and all elements of nums2 are sorted in non-decreasing order
Examples
Input: ([1,2,3,0,0,0], 3, [2,5,6], 3)
Expected Output: [1,2,2,3,5,6]
Explanation: The two sorted arrays [1,2,3] and [2,5,6] merge into [1,2,2,3,5,6].
Input: ([0], 0, [1], 1)
Expected Output: [1]
Explanation: nums1 has no valid original elements, so it becomes nums2.
Input: ([1], 1, [], 0)
Expected Output: [1]
Explanation: nums2 is empty, so nums1 is unchanged.
Input: ([2,0], 1, [1], 1)
Expected Output: [1,2]
Explanation: The smaller nums2 value must be placed before the original nums1 value.
Input: ([-3,-1,0,0,0], 2, [-2,-2,4], 3)
Expected Output: [-3,-2,-2,-1,4]
Explanation: Negative numbers and duplicates are handled normally.
Hints
- Try filling nums1 from the back so that unprocessed values are not overwritten.
- Compare the largest remaining values of nums1 and nums2.
Part 2: Merge Three Sorted Arrays
Constraints
- 0 <= len(A), len(B), len(C) <= 200000
- The total number of elements is at most 600000
- Values fit in a 32-bit signed integer
- Each input array is sorted in non-decreasing order
Examples
Input: ([1,4], [2,3], [0,5])
Expected Output: [0,1,2,3,4,5]
Explanation: All three arrays are merged into sorted order.
Input: ([], [], [])
Expected Output: []
Explanation: All inputs are empty, so the result is empty.
Input: ([1,1], [1], [1,2])
Expected Output: [1,1,1,1,2]
Explanation: Duplicates are preserved.
Input: ([], [-2,0], [-3,4])
Expected Output: [-3,-2,0,4]
Explanation: One array may be empty.
Input: ([1,3,7], [2,6], [4,5,8,9])
Expected Output: [1,2,3,4,5,6,7,8,9]
Explanation: Arrays of different lengths are supported.
Hints
- Maintain one pointer into each array.
- At each step, append the smallest currently pointed-to value.
Part 3: Merge Three Sorted Arrays Without Duplicates
Constraints
- 0 <= len(A), len(B), len(C) <= 200000
- The total number of elements is at most 600000
- Values fit in a 32-bit signed integer
- Each input array is sorted in non-decreasing order
Examples
Input: ([1,2,2], [2,3], [1,4])
Expected Output: [1,2,3,4]
Explanation: Values 1 and 2 appear multiple times but are returned once.
Input: ([], [], [])
Expected Output: []
Explanation: No input values means no output values.
Input: ([1,1,1], [], [1,1])
Expected Output: [1]
Explanation: All values are duplicates of 1.
Input: ([-3,-1,2], [-2,-1,2,5], [-3,0])
Expected Output: [-3,-2,-1,0,2,5]
Explanation: The result is sorted and contains each distinct value once.
Input: ([1,3,5], [2,3,4], [4,5,6])
Expected Output: [1,2,3,4,5,6]
Explanation: Duplicates across arrays are removed.
Hints
- After finding the smallest current value, advance past all copies of that value in all three arrays.
- Because the arrays are sorted, duplicates will be adjacent within each array.
Part 4: Round-Robin Task Scheduler
Constraints
- 0 <= len(tasks) <= 200000
- 1 <= q <= 1000000000
- 0 <= arrival_time <= 1000000000
- 1 <= burst_time <= 1000000000
- task_id values are integers and are not -1
- The number of output segments is bounded by the total number of time slices
Examples
Input: ([(1,0,5),(2,1,3),(3,2,1)], 2)
Expected Output: [(1,0,2),(2,2,4),(3,4,5),(1,5,7),(2,7,8),(1,8,9)]
Explanation: Tasks 2 and 3 arrive during task 1's first time slice and are queued before task 1 is requeued.
Input: ([(10,3,2)], 5)
Expected Output: [(-1,0,3),(10,3,5)]
Explanation: The CPU is idle from time 0 to 3 before task 10 arrives.
Input: ([], 3)
Expected Output: []
Explanation: With no tasks, there are no execution segments.
Input: ([(1,0,4),(2,0,2),(3,1,3)], 2)
Expected Output: [(1,0,2),(2,2,4),(3,4,6),(1,6,8),(3,8,9)]
Explanation: Tasks 1 and 2 arrive together, so their input order is preserved.
Input: ([(2,5,3),(1,0,2)], 2)
Expected Output: [(1,0,2),(-1,2,5),(2,5,7),(2,7,8)]
Explanation: The input is unsorted, and an idle gap occurs between task 1 finishing and task 2 arriving.
Hints
- Sort tasks by arrival time, preserving input order for equal arrivals.
- Use a queue to store ready tasks with their remaining runtime.
Part 5: Simplified Stock Trading Simulator
Constraints
- 0 <= len(events) <= 200000
- amount, qty, and price are positive integers
- Symbols are non-empty strings
- All cash computations fit in signed 64-bit integers
- Events are validly formatted and time-ordered
Examples
Input: ([('DEPOSIT',1000),('BUY','AAPL',5,100),('SELL','AAPL',2,120)],)
Expected Output: (740, {'AAPL': 3}, [])
Explanation: Cash becomes 1000 - 500 + 240 = 740, and 3 AAPL shares remain.
Input: ([('BUY','MSFT',1,10),('DEPOSIT',50),('BUY','MSFT',3,20),('BUY','MSFT',2,20),('SELL','MSFT',3,25)],)
Expected Output: (10, {'MSFT': 2}, [0, 2, 4])
Explanation: The first buy has no cash, the second buy is too expensive, and the sell exceeds the position.
Input: ([],)
Expected Output: (0, {}, [])
Explanation: No events means zero cash, no positions, and no rejected events.
Input: ([('DEPOSIT',100),('BUY','ABC',2,30),('SELL','ABC',2,40)],)
Expected Output: (120, {}, [])
Explanation: The final ABC position is zero, so it is omitted.
Input: ([('DEPOSIT',500),('BUY','A',2,100),('BUY','B',3,50),('SELL','A',1,120)],)
Expected Output: (270, {'A': 1, 'B': 3}, [])
Explanation: Multiple symbols are tracked independently.
Hints
- Keep one integer cash balance and a dictionary of symbol quantities.
- Validate an event before mutating cash or positions.
Part 6: Trading Simulator with Average Cost Basis
Constraints
- 0 <= len(events) <= 200000
- amount, qty, and price are positive integers
- Symbols are non-empty strings
- All cash computations fit in signed 64-bit integers
- Events are validly formatted and time-ordered
Examples
Input: ([('DEPOSIT',1000),('BUY','AAPL',2,100),('BUY','AAPL',3,120),('SELL','AAPL',1,150)],)
Expected Output: (590, {'AAPL': 4}, {'AAPL': 112.0}, [])
Explanation: The average cost is (2*100 + 3*120) / 5 = 112.0 and remains unchanged after selling 1 share.
Input: ([],)
Expected Output: (0, {}, {}, [])
Explanation: No events produce no positions or average costs.
Input: ([('DEPOSIT',100),('BUY','X',5,10),('SELL','X',5,12)],)
Expected Output: (110, {}, {}, [])
Explanation: The full position is sold, so X is removed from positions and average costs.
Input: ([('DEPOSIT',50),('BUY','A',2,20),('BUY','A',2,20),('SELL','A',3,30)],)
Expected Output: (10, {'A': 2}, {'A': 20.0}, [2, 3])
Explanation: The second buy is rejected due to insufficient cash, and the sell is rejected due to insufficient shares.
Input: ([('DEPOSIT',100),('BUY','B',1,10),('BUY','B',2,11)],)
Expected Output: (68, {'B': 3}, {'B': 10.666667}, [])
Explanation: The weighted average cost is (1*10 + 2*11) / 3 = 10.666667 after rounding.
Hints
- For an accepted buy, combine old cost basis and new purchase cost using a weighted average.
- Selling shares reduces quantity but leaves the average cost of the remaining shares unchanged.
Part 7: Trading Simulator with FIFO Realized P&L
Constraints
- 0 <= len(events) <= 200000
- amount, qty, and price are positive integers
- Symbols are non-empty strings
- All cash and P&L computations fit in signed 64-bit integers
- Events are validly formatted and time-ordered
Examples
Input: ([('DEPOSIT',2000),('BUY','A',5,100),('BUY','A',5,110),('SELL','A',7,120)],)
Expected Output: (1790, {'A': 3}, 120, [])
Explanation: The sell consumes 5 shares bought at 100 and 2 shares bought at 110, for P&L 5*20 + 2*10 = 120.
Input: ([('DEPOSIT',500),('BUY','X',4,50),('SELL','X',2,40)],)
Expected Output: (380, {'X': 2}, -20, [])
Explanation: Selling below cost realizes a loss of 2*(40 - 50) = -20.
Input: ([('SELL','A',1,10),('DEPOSIT',100),('BUY','A',2,30),('BUY','A',2,30),('SELL','A',5,40)],)
Expected Output: (40, {'A': 2}, 0, [0, 3, 4])
Explanation: The first sell has no shares, the second buy lacks cash, and the final sell exceeds the position.
Input: ([],)
Expected Output: (0, {}, 0, [])
Explanation: No events means no cash, positions, P&L, or rejections.
Input: ([('DEPOSIT',300),('BUY','A',1,100),('BUY','A',1,120),('SELL','A',2,130)],)
Expected Output: (340, {}, 40, [])
Explanation: Both lots are fully sold, realizing 30 + 10 = 40 profit and leaving no position.
Hints
- Maintain a FIFO queue of buy lots for each symbol, where each lot stores remaining quantity and purchase price.
- Each accepted sell may consume multiple lots, but each buy lot is removed at most once overall.