完成所有工作的最短时间
难度:
标签:
题目描述
代码结果
运行时间: 36 ms, 内存: 16.0 MB
/*
思路:
利用Java Stream API,优化代码的可读性。
首先获取作业数组的最大值和总和。
然后在二分查找过程中,使用stream来获取workers的工作时间和。判断能否在给定的最大工作时间下完成任务。
*/
import java.util.Arrays;
public class Solution {
public int minimumTimeRequired(int[] jobs, int k) {
int left = Arrays.stream(jobs).max().orElse(0);
int right = Arrays.stream(jobs).sum();
while (left < right) {
int mid = (left + right) / 2;
if (canFinish(jobs, k, mid)) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
private boolean canFinish(int[] jobs, int k, int maxTime) {
int[] workers = new int[k];
return canDistribute(jobs, workers, 0, maxTime);
}
private boolean canDistribute(int[] jobs, int[] workers, int index, int maxTime) {
if (index == jobs.length) return true;
for (int i = 0; i < workers.length; i++) {
if (workers[i] + jobs[index] <= maxTime) {
workers[i] += jobs[index];
if (canDistribute(jobs, workers, index + 1, maxTime)) return true;
workers[i] -= jobs[index];
}
if (workers[i] == 0) break; // 剪枝
}
return false;
}
}
解释
方法:
该题解采用二分搜索与回溯的方法来解决问题。首先对工作时间数组进行排序,以便优先尝试分配耗时较长的工作,这有助于尽早达到最大工作时间的限制。在二分搜索的每一步,使用中值 'mid' 作为尝试的最大工作时间限制。在回溯部分,使用一个辅助函数 'check' 来递归尝试将每项工作分配给工人,直到所有工作都能在 'mid' 时间内被成功分配,或者无法分配为止。如果可以成功分配,则缩小搜索范围,否则增大 'mid'。通过这种方式逐步缩小可能的最大工作时间,直到找到最小可能值。
时间复杂度:
O((log(sum(jobs) - max(jobs))) * k^n)
空间复杂度:
O(n + k)
代码细节讲解
🦆
二分搜索的上界和下界分别是`sum(jobs)`和`max(jobs)`的最大值除以工人数`k`,这样设定的理由是什么?
▷🦆
二分搜索的终止条件是当`l < r`,但为什么在找到可行的`mid`后,将`r`设置为`mid`而不是`mid-1`?
▷