LeetCode 2432 - The Employee That Worked on the Longest Task
The problem asks us to identify which employee worked the task with the longest duration given a sequence of tasks completed by employees. Each task is represented in logs[i] = [idi, leaveTimei], where idi is the employee id and leaveTimei is the time the task was completed.
Difficulty: 🟢 Easy
Topics: Array
Solution
Problem Understanding
The problem asks us to identify which employee worked the task with the longest duration given a sequence of tasks completed by employees. Each task is represented in logs[i] = [idi, leaveTimei], where idi is the employee id and leaveTimei is the time the task was completed. The start time of each task is implicitly defined: the first task starts at 0 and each subsequent task starts immediately after the previous task ends. The employee that worked the task with the maximum duration should be returned, and in case of ties, the smallest employee id should be returned.
The input constraints are small: n and logs.length are at most 500. All leaveTimei values are unique and strictly increasing, and consecutive tasks are worked on by different employees. This guarantees that each task has a positive duration and that there are no ambiguities in task ordering. Edge cases include multiple tasks sharing the maximum duration or the first or last task being the longest.
Approaches
A naive approach would explicitly calculate the duration of each task and store all durations in a list, then search for the maximum duration and retrieve the corresponding employee id. This is correct but requires a separate traversal and extra space, which is unnecessary since we can track the maximum dynamically.
The optimal approach leverages the fact that task durations can be computed on the fly and we only need the current maximum. We iterate through the logs, compute the task duration for each task by subtracting the previous task's leave time (or 0 for the first task), and maintain a record of the maximum duration and corresponding employee id. If multiple tasks have the same maximum duration, we update the id only if the current employee id is smaller. This method is linear in time and uses constant extra space.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n) | O(n) | Stores all task durations explicitly and searches for max |
| Optimal | O(n) | O(1) | Tracks maximum duration and corresponding employee id on the fly |
Algorithm Walkthrough
-
Initialize
max_durationto0andhardest_employeeto0. These will track the longest task duration and the corresponding employee id. -
Initialize
prev_timeto0. This variable represents the end time of the previous task and is used to compute the current task's duration. -
Iterate over each task in
logs. For each task: -
Compute the task duration as
duration = leaveTimei - prev_time. -
If
duration > max_duration, updatemax_duration = durationandhardest_employee = idi. -
If
duration == max_durationandidi < hardest_employee, updatehardest_employee = idito handle ties. -
Update
prev_time = leaveTimeifor the next iteration. -
After iterating through all tasks, return
hardest_employee.
Why it works: The algorithm maintains the invariant that hardest_employee always represents the employee who has completed the task with the maximum duration so far. Since each task's duration is uniquely determined by consecutive leave times, this guarantees correctness. Ties are resolved by comparing employee ids at the moment of equality.
Python Solution
from typing import List
class Solution:
def hardestWorker(self, n: int, logs: List[List[int]]) -> int:
max_duration = 0
hardest_employee = 0
prev_time = 0
for emp_id, leave_time in logs:
duration = leave_time - prev_time
if duration > max_duration or (duration == max_duration and emp_id < hardest_employee):
max_duration = duration
hardest_employee = emp_id
prev_time = leave_time
return hardest_employee
Explanation: We initialize tracking variables and iterate through each log. For each task, we compute the duration relative to the previous task’s finish time. Whenever a longer duration is found, we update both max_duration and hardest_employee. If the duration ties with the current maximum, we ensure the employee with the smaller id is selected. The final value of hardest_employee is returned.
Go Solution
func hardestWorker(n int, logs [][]int) int {
maxDuration := 0
hardestEmployee := 0
prevTime := 0
for _, log := range logs {
empID := log[0]
leaveTime := log[1]
duration := leaveTime - prevTime
if duration > maxDuration || (duration == maxDuration && empID < hardestEmployee) {
maxDuration = duration
hardestEmployee = empID
}
prevTime = leaveTime
}
return hardestEmployee
}
Explanation: The Go solution mirrors the Python approach. Slices are used to access log entries, and variables maxDuration, hardestEmployee, and prevTime track the same information. Ties are resolved by comparing employee ids in the same way. No additional memory is used beyond a few integers.
Worked Examples
Example 1:
| Task | emp_id | leave_time | prev_time | duration | max_duration | hardest_employee |
|---|---|---|---|---|---|---|
| 0 | 0 | 3 | 0 | 3 | 3 | 0 |
| 1 | 2 | 5 | 3 | 2 | 3 | 0 |
| 2 | 0 | 9 | 5 | 4 | 4 | 0 |
| 3 | 1 | 15 | 9 | 6 | 6 | 1 |
Result: 1
Example 2:
| Task | emp_id | leave_time | prev_time | duration | max_duration | hardest_employee |
|---|---|---|---|---|---|---|
| 0 | 1 | 1 | 0 | 1 | 1 | 1 |
| 1 | 3 | 7 | 1 | 6 | 6 | 3 |
| 2 | 2 | 12 | 7 | 5 | 6 | 3 |
| 3 | 7 | 17 | 12 | 5 | 6 | 3 |
Result: 3
Example 3:
| Task | emp_id | leave_time | prev_time | duration | max_duration | hardest_employee |
|---|---|---|---|---|---|---|
| 0 | 0 | 10 | 0 | 10 | 10 | 0 |
| 1 | 1 | 20 | 10 | 10 | 10 | 0 |
Result: 0
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | We iterate through the logs array once, computing durations on the fly. |
| Space | O(1) | Only a few integer variables are used regardless of input size. |
The linear time complexity is efficient given the constraints (n and logs.length ≤ 500). Constant space ensures minimal memory usage.
Test Cases
# Provided examples
assert Solution().hardestWorker(10, [[0,3],[2,5],[0,9],[1,15]]) == 1 # Longest task 6 by emp 1
assert Solution().hardestWorker(26, [[1,1],[3,7],[2,12],[7,17]]) == 3 # Longest task 6 by emp 3
assert Solution().hardestWorker(2, [[0,10],[1,20]]) == 0 # Tie duration, smaller id
# Edge cases
assert Solution().hardestWorker(2, [[1,1],[0,2]]) == 0 # First task smaller, second longer
assert Solution().hardestWorker(3, [[2,2],[1,5],[0,7]]) == 1 # Middle task longest
assert Solution().hardestWorker(4, [[0,2],[1,4],[2,6],[3,8]]) == 0 # All durations equal, smallest id
assert Solution().hardestWorker(5, [[4,1],[3,3],[2,6],[1,10],[0,15]]) == 0 # Last task longest
| Test | Why |
|---|---|
| Example 1 | Basic functionality with varying durations |
| Example 2 | Longest task in the middle |
| Example 3 | Tie in duration between first and last task |
| First task smaller, second longer | Checks dynamic update of longest task |
| Middle task longest | Validates proper handling of max in middle |
| All equal durations | Ensures tie resolution by smallest id |
| Last task longest | Confirms last task is properly considered |
Edge Cases
Tie for longest duration: If multiple tasks share the same maximum duration, the smallest employee id should be returned. This could trip up naive implementations that only track the last occurrence. Our algorithm explicitly checks for ties and updates the employee id accordingly.
**First or last task