You are given an integer array jobs, where jobs[i] is the amount of time it takes to complete the ith job.
There are k workers that you can assign jobs to. Each job should be assigned to exactly one worker. The working time of a worker is the sum of the time it takes to complete all jobs assigned to them. Your goal is to devise an optimal assignment such that the maximum working time of any worker is minimized.
Return the minimum possible maximum working time of any assignment.
Example 1:
Input: jobs = [3,2,3], k = 3 Output: 3 Explanation: By assigning each person one job, the maximum time is 3.
Example 2:
Input: jobs = [1,2,4,7,8], k = 2 Output: 11 Explanation: Assign the jobs the following way: Worker 1: 1, 2, 8 (working time = 1 + 2 + 8 = 11) Worker 2: 4, 7 (working time = 4 + 7 = 11) The maximum working time is 11.
Constraints:
1 <= k <= jobs.length <= 121 <= jobs[i] <= 107When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force method for finding the minimum time to finish all jobs involves exploring every possible way to assign jobs to workers. We systematically try all combinations of job assignments. We then find the best outcome from all the tried scenarios.
Here's how the algorithm would work step-by-step:
def find_minimum_time_to_finish_all_jobs(job_durations, number_of_workers):
minimum_time = float('inf')
def calculate_minimum_time_recursive(index, worker_assignments):
nonlocal minimum_time
# Base case: all jobs have been assigned
if index == len(job_durations):
maximum_worker_time = 0
for worker_index in range(number_of_workers):
maximum_worker_time = max(maximum_worker_time, sum(worker_assignments[worker_index]))
minimum_time = min(minimum_time, maximum_worker_time)
return
# Try assigning the current job to each worker
for worker_index in range(number_of_workers):
# Create a new assignment configuration
new_worker_assignments = [worker_assignments[i][:] for i in range(number_of_workers)]
new_worker_assignments[worker_index].append(job_durations[index])
# Recursively explore the next job assignment
calculate_minimum_time_recursive(index + 1, new_worker_assignments)
# Initialize worker assignments as empty lists for each worker
initial_worker_assignments = [[] for _ in range(number_of_workers)]
# Start the recursive process
calculate_minimum_time_recursive(0, initial_worker_assignments)
return minimum_timeThe best way to solve this problem is to cleverly guess possible completion times and then check if those guesses are actually feasible. We use a binary search approach to efficiently narrow down the correct minimum completion time. This is much better than trying all possible worker assignments.
Here's how the algorithm would work step-by-step:
def find_minimum_time_to_finish_all_jobs(jobs, number_of_workers):
start_time = max(jobs)
end_time = sum(jobs)
while start_time < end_time:
mid_time = (start_time + end_time) // 2
# Check if it's possible to complete within mid_time
if is_possible_to_complete(jobs, number_of_workers, mid_time):
end_time = mid_time
else:
start_time = mid_time + 1
return start_time
def is_possible_to_complete(jobs, number_of_workers, max_time_per_worker):
workers_needed = 1
current_worker_time = 0
# Iterate through each job and assign to worker greedily
for job_duration in jobs:
if job_duration > max_time_per_worker:
return False
if current_worker_time + job_duration <= max_time_per_worker:
current_worker_time += job_duration
else:
# Need a new worker if current can't complete the job.
workers_needed += 1
current_worker_time = job_duration
# If the needed workers exceed the number, not possible.
if workers_needed <= number_of_workers:
return True
else:
return False
# The is_possible_to_complete checks if a completion time is feasible.
# Based on this result, we adjust the search space
# Binary search to find the minimum completion time.
# We want to find the smallest time all the jobs can be completed| Case | How to Handle |
|---|---|
| Empty jobs array | Return 0 immediately as there are no jobs to process. |
| Single job in the array | Assign the single job to one worker, and the minimum time is the job's duration. |
| Jobs array with all zero durations | The minimum time is 0 since all jobs complete instantly regardless of worker assignments. |
| Large number of jobs and limited workers | The binary search range must be appropriately defined to avoid potential integer overflow issues during mid calculation. |
| Jobs array with very large job durations | Integer overflow must be considered when summing job durations; using long data types can prevent this. |
| Number of workers is greater than or equal to the number of jobs | The minimum time is equal to the duration of the longest job. |
| Input contains negative job durations | Throw an IllegalArgumentException as job durations cannot be negative. |
| Maximum integer value for the duration of one or more jobs | Handle possible integer overflows during the calculation of the total duration and the binary search mid-point. |