Assign tasks to workers with types and accounts
Company: Stripe
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question evaluates algorithmic scheduling and dynamic resource-allocation skills, including priority-queue/heap usage, time-based simulation, and scalable data-structure design for account affinity and heterogeneous worker speeds.
Part 1: Fastest Eligible Task Assignment
Constraints
- 0 <= N <= 5000
- 0 <= W <= 5000
- N * W <= 2000000
- arrival is non-decreasing
- duration[i] is a positive integer for every task
- All speed multipliers are positive integers
- Every task has at least one eligible worker
- Task type labels are strings
Examples
Input: ([0, 1, 2], [5, 2, 1], ['A', 'A', 'B'], [{'A': 1, 'B': 5}, {'A': 2}, {'B': 1}])
Expected Output: [0, 1, 2]
Explanation: Task 0 goes to worker 0 because it finishes at 5. Task 1 goes to worker 1 because worker 0 is busy until 5. Task 2 goes to worker 2 because it is much faster for B.
Input: ([0, 0], [2, 1], ['X', 'X'], [{'X': 2}, {'X': 2}, {'X': 3}])
Expected Output: [0, 1]
Explanation: For task 0, workers 0 and 1 both finish at time 4, so worker 0 wins by ID. For task 1, worker 1 is free and finishes earliest.
Input: ([0, 0, 3], [10, 4, 1], ['A', 'A', 'A'], [{'A': 1}, {'A': 3}])
Expected Output: [0, 1, 0]
Explanation: Worker 0 is faster but becomes busy after task 0. Worker 1 gets task 1 because it can finish earlier. Worker 0 gets task 2 because it still finishes before worker 1.
Input: ([0, 1, 1, 10], [3, 2, 4, 1], ['A', 'B', 'A', 'B'], [{'A': 2}, {'B': 1}, {'A': 1, 'B': 3}])
Expected Output: [2, 1, 2, 1]
Explanation: Different task types have different eligible worker sets. Each task is assigned using earliest finish time among workers that support its type.
Input: ([], [], [], [])
Expected Output: []
Explanation: There are no tasks, so no assignments are made.
Hints
- Maintain an array next_free where next_free[w] is the earliest time worker w can start a new task.
- For each eligible worker, compute finish and compare the tuple (finish, workerId).
Part 2: Account-Sticky Task Assignment
Constraints
- 0 <= N <= 5000
- 0 <= W <= 5000
- N * W <= 2000000
- arrival is non-decreasing
- duration[i] is a positive integer for every task
- All speed multipliers are positive integers
- Every task has at least one eligible worker
- Task type labels and account labels are strings
Examples
Input: ([0, 1, 2], [5, 2, 1], ['A', 'A', 'A'], ['acct', 'acct', 'other'], [{'A': 1}, {'A': 2}])
Expected Output: [0, 0, 1]
Explanation: Task 0 assigns account acct to worker 0. Task 1 must also go to worker 0 due to stickiness, even though worker 1 could finish earlier. Task 2 has a different account and goes to worker 1.
Input: ([0, 1, 2, 3], [4, 2, 1, 1], ['A', 'B', 'B', 'A'], ['x', 'x', 'x', 'x'], [{'A': 1}, {'B': 1}, {'A': 2, 'B': 3}])
Expected Output: [0, 1, 1, 0]
Explanation: Account x first maps to worker 0. Worker 0 cannot process B, so task 1 falls back to worker 1 and remaps x. Task 2 sticks to worker 1. Worker 1 cannot process A, so task 3 falls back and chooses worker 0 by the finish-time then ID rule.
Input: ([0, 0, 1], [10, 1, 1], ['A', 'A', 'A'], ['a', 'b', 'a'], [{'A': 1}, {'A': 1}])
Expected Output: [0, 1, 0]
Explanation: Account a is owned by worker 0 after task 0. Task 2 must wait for worker 0 due to stickiness, even though worker 1 is free.
Input: ([], [], [], [], [])
Expected Output: []
Explanation: There are no tasks, so the owner map remains empty and no assignments are returned.
Hints
- Before doing the fastest-worker scan, check whether the task's account already has an owner that supports the task type.
- When fallback assignment is used because the previous owner is missing or unsupported, overwrite the owner mapping with the newly chosen worker.