Implement a Time-Aware Task Manager
Company: Anthropic
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: hard
Interview Round: Technical Screen
Quick Answer: This question evaluates the ability to design and implement in-memory data structures and algorithms for time-aware state management, including per-user task versioning, expiration (TTL), and historical queries.
Part 1: Basic Task Manager with Creation and Active Listing
Constraints
- 0 <= number of tasks, number of queries <= 200000
- len(task_users) == len(task_ids) == len(task_contents) == len(created_at)
- len(query_users) == len(query_times)
- Each task_id is unique
- Timestamps are integers
- If multiple tasks for the same user have the same creation time, preserve their original input order
Examples
Input: (['u1', 'u1', 'u2'], ['t1', 't2', 't3'], ['buy milk', 'write code', 'read'], [1, 3, 2], ['u1', 'u2', 'u1'], [0, 10, 3])
Expected Output: [[], [['t3', 'read']], [['t1', 'buy milk'], ['t2', 'write code']]]
Explanation: u1 has nothing at time 0. u2 has t3 by time 10. u1 has both tasks by time 3.
Input: (['u1', 'u1', 'u1'], ['t2', 't1', 't3'], ['B', 'A', 'C'], [5, 5, 6], ['u1', 'u1'], [5, 6])
Expected Output: [[['t2', 'B'], ['t1', 'A']], [['t2', 'B'], ['t1', 'A'], ['t3', 'C']]]
Explanation: At the same creation time, the two tasks at time 5 stay in their original input order.
Input: ([], [], [], [], ['u1'], [10])
Expected Output: [[]]
Explanation: Edge case: no tasks exist.
Input: (['u1'], ['t1'], ['A'], [7], ['u2', 'u1'], [7, 6])
Expected Output: [[], []]
Explanation: A query for a different user and a query before creation both return empty lists.
Hints
- Group tasks by user first, instead of scanning all tasks for every query.
- After sorting one user's tasks by creation time, binary search tells you how many tasks already exist at a given timestamp.
Part 2: Task Manager with Expiration and TTL
Constraints
- 0 <= number of operations <= 200000
- len(op_types) == len(op_users) == len(op_task_ids) == len(op_contents) == len(op_times) == len(op_expirations)
- op_times are strictly increasing
- Each task_id is unique and is created before any set_ttl that refers to it
- Each task has at most one TTL assignment
- If a task expires at time e, it must not appear in any list at time e or later
Examples
Input: (['create', 'create', 'list', 'set_ttl', 'list', 'list'], ['u1', 'u1', 'u1', '', 'u1', 'u1'], ['t1', 't2', '', 't1', '', ''], ['A', 'B', '', '', '', ''], [1, 2, 3, 4, 5, 6], [-1, -1, -1, 6, -1, -1])
Expected Output: [[['t1', 'A'], ['t2', 'B']], [['t1', 'A'], ['t2', 'B']], [['t2', 'B']]]
Explanation: t1 gets expiration 6 at time 4. It still appears at time 5, but not at time 6.
Input: (['create', 'create', 'set_ttl', 'list', 'list'], ['u1', 'u2', '', 'u2', 'u1'], ['t1', 't2', 't2', '', ''], ['A', 'B', '', '', ''], [1, 2, 3, 4, 5], [-1, -1, 4, -1, -1])
Expected Output: [[], [['t1', 'A']]]
Explanation: u2's only task expires exactly at time 4, so it is already gone for the list at time 4.
Input: (['create', 'set_ttl', 'list'], ['u1', '', 'u1'], ['t1', 't1', ''], ['A', '', ''], [1, 2, 3], [-1, 2, -1])
Expected Output: [[]]
Explanation: Edge case: assigning expiration equal to the current time makes the task inactive immediately from that time onward.
Input: (['list'], ['u1'], [''], [''], [1], [-1])
Expected Output: [[]]
Explanation: Edge case: listing before any task is created returns an empty list.
Hints
- Because operations are already chronological, you only need to move time forward once.
- A min-heap can tell you which tasks should expire before the next operation, while an insertion-ordered map per user preserves listing order.
Part 3: Historical Reconstruction of a User's Task List
Constraints
- 0 <= number of tasks, expirations, queries <= 200000
- len(task_users) == len(task_ids) == len(task_contents) == len(created_at)
- len(exp_task_ids) == len(exp_times)
- len(query_users) == len(query_times)
- Each task_id is unique, and each task appears at most once in the expiration arrays
- If a task expires at time e, it must not appear in a query at time e or later
Examples
Input: (['u1', 'u1', 'u2'], ['t1', 't2', 't3'], ['A', 'B', 'C'], [1, 4, 2], ['t1', 't3'], [5, 3], ['u1', 'u1', 'u2', 'u1'], [1, 5, 3, 4])
Expected Output: [[['t1', 'A']], [['t2', 'B']], [], [['t1', 'A'], ['t2', 'B']]]
Explanation: Queries are not sorted. At time 5, t1 has expired; at time 3, u2's task is already expired because expiration is inclusive at that timestamp.
Input: (['u1', 'u1'], ['t1', 't2'], ['A', 'B'], [2, 2], ['t1'], [2], ['u1'], [2])
Expected Output: [[['t2', 'B']]]
Explanation: Edge case: t1 is created and expires at the same timestamp, so it should not appear in the historical result at that time.
Input: ([], [], [], [], [], [], ['u1', 'u2'], [0, 10])
Expected Output: [[], []]
Explanation: Edge case: no tasks exist at all.
Input: (['u1', 'u1'], ['t2', 't1'], ['B', 'A'], [5, 5], [], [], ['u1'], [5])
Expected Output: [[['t2', 'B'], ['t1', 'A']]]
Explanation: Two tasks share the same creation time, so the original input order is preserved.
Hints
- Think of creation and expiration as timeline events.
- If you sort both events and queries by time, you can sweep once from left to right and answer all historical queries efficiently.