Build a Progressive Employee Tracker
AnthropicSoftware Engineer · OnsiteLast updated
Design an in-memory attendance and payroll tracking system that manages shift lifecycles, deferred rate promotions, overlapping bonus windows, and duration rankings.
Problem Statement
Design an in-memory employee attendance and payroll management class, EmployeeTracker. The system tracks employee shifts, hourly rates, promotions, global bonus intervals, and total time worked.
Implement the EmployeeTracker class with the following methods:
-
register_employee(emp_id: str, initial_hourly_rate: float) -> None: Registers a new employee with a base hourly rate. -
schedule_promotion(emp_id: str, effective_time: int, new_hourly_rate: float) -> None: Schedules a rate update foremp_id. The promotion takes effect at the employee's first clock-in at or aftereffective_time. An ongoing shift active acrosseffective_timeis not affected; its rate remains snapshotted at its initial clock-in rate. -
add_bonus_window(start_time: int, end_time: int) -> None: Adds a global bonus window[start_time, end_time). Any portion of a shift overlapping with one or more bonus windows is paid at2.0xthe shift's snapshotted rate. Overlapping or contiguous bonus windows must be merged so bonus pay is applied at most once per time unit. -
clock_in(emp_id: str, timestamp: int) -> None: Clocks in an employee. Applies any scheduled promotions whoseeffective_time None: Clocks out the employee, closing the shift[clock_in_time, timestamp). Accrues total completed duration and earned pay. -
get_total_pay(emp_id: str) -> float: Returns total earnings from all closed shifts for the employee. Returns0.0if no shifts have been closed. -
get_top_k_worked(k: int) -> list[str]: Returns theemp_ids of the topkemployees by total closed shift duration in descending order. Break ties lexicographically byemp_idin ascending order.
All timestamps and durations are integers representing hours.
Constraints
- Timestamps are non-negative integers (
0 <= timestamp <= 10^9). - Calls to
clock_inandclock_outfor any given employee are guaranteed to be strictly valid (alternating, non-empty, and strictly increasing timestamps). - Bonus windows satisfy
0 <= start_time < end_time <= 10^9. - At most
10^5operations across all methods.
Example
tracker = EmployeeTracker()
tracker.register_employee("E1", 20.0)
tracker.add_bonus_window(2, 5)
tracker.add_bonus_window(4, 7) # Merged window: [2, 7)
tracker.clock_in("E1", 1)
tracker.clock_out("E1", 4)
# Shift [1, 4): duration 3 hours.
# Overlap with [2, 7) is [2, 4) (2 hrs). Normal portion: [1, 2) (1 hr).
# Pay: (1 hr * 20.0) + (2 hrs * 20.0 * 2.0) = 20.0 + 80.0 = 100.0
tracker.schedule_promotion("E1", 5, 30.0)
tracker.clock_in("E1", 6)
# Timestamp 6 >= 5, so rate is updated to 30.0 for this shift.
tracker.clock_out("E1", 9)
# Shift [6, 9): duration 3 hours.
# Overlap with [2, 7) is [6, 7) (1 hr bonus). Normal portion: [7, 9) (2 hrs).
# Pay: (1 hr * 30.0 * 2.0) + (2 hrs * 30.0) = 60.0 + 60.0 = 120.0
assert tracker.get_total_pay("E1") == 220.0
assert tracker.get_top_k_worked(1) == ["E1"]
Hints
Hint 1
Maintain bonus windows in a sorted, disjoint interval list by merging overlapping or adjacent intervals upon insertion or query.
Hint 2
Store scheduled promotions in a priority queue or sorted list per employee so they can be popped when a clock-in occurs at or after their effective times.
Hint 3
To compute the bonus overlap for a shift [start, end), use binary search on the disjoint bonus intervals rather than checking unit-by-unit.
Hint 4
For get_top_k_worked, maintain total durations per employee and either use a min-heap of size k or sort on demand depending on call frequency.
Follow-up questions
- How would you optimize `add_bonus_window` and shift overlap calculation if timestamps were dense and calls were heavily write-heavy vs. read-heavy?
- How would you handle retroactive shift modifications or cancellations without recomputing all pay from scratch?
- If promotion rules depended on hours worked (e.g., automatically promoting an employee after 500 completed hours) rather than scheduled timestamps, how would you restructure the event processing?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.