为了提高自己的代码能力,小张制定了 LeetCode
刷题计划,他选中了 LeetCode
题库中的 n
道题,编号从 0
到 n-1
,并计划在 m
天内按照题目编号顺序刷完所有的题目(注意,小张不能用多天完成同一题)。
在小张刷题计划中,小张需要用 time[i]
的时间完成编号 i
的题目。此外,小张还可以使用场外求助功能,通过询问他的好朋友小杨题目的解法,可以省去该题的做题时间。为了防止“小张刷题计划”变成“小杨刷题计划”,小张每天最多使用一次求助。
我们定义 m
天中做题时间最多的一天耗时为 T
(小杨完成的题目不计入做题总时间)。请你帮小张求出最小的 T
是多少。
示例 1:
输入:
time = [1,2,3,3], m = 2
输出:
3
解释:第一天小张完成前三题,其中第三题找小杨帮忙;第二天完成第四题,并且找小杨帮忙。这样做题时间最多的一天花费了 3 的时间,并且这个值是最小的。
示例 2:
输入:
time = [999,999,999], m = 4
输出:
0
解释:在前三天中,小张每天求助小杨一次,这样他可以在三天内完成所有的题目并不花任何时间。
限制:
1 <= time.length <= 10^5
1 <= time[i] <= 10000
1 <= m <= 1000
方法一:贪心 + 二分查找
我们可以将题意转换为,将题目最多分成
我们定义二分查找的左边界
我们定义函数
我们可以用贪心的方法来判断是否存在这样的分组方案。我们从左到右遍历题目,将题目耗时加入当前总耗时
时间复杂度
class Solution:
def minTime(self, time: List[int], m: int) -> int:
def check(t):
s = mx = 0
d = 1
for x in time:
s += x
mx = max(mx, x)
if s - mx > t:
d += 1
s = mx = x
return d <= m
return bisect_left(range(sum(time)), True, key=check)
class Solution {
public int minTime(int[] time, int m) {
int left = 0, right = 0;
for (int x : time) {
right += x;
}
while (left < right) {
int mid = (left + right) >> 1;
if (check(mid, time, m)) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
private boolean check(int t, int[] time, int m) {
int s = 0, mx = 0;
int d = 1;
for (int x : time) {
s += x;
mx = Math.max(mx, x);
if (s - mx > t) {
s = x;
mx = x;
++d;
}
}
return d <= m;
}
}
class Solution {
public:
int minTime(vector<int>& time, int m) {
int left = 0, right = 0;
for (int x : time) {
right += x;
}
auto check = [&](int t) -> bool {
int s = 0, mx = 0;
int d = 1;
for (int x : time) {
s += x;
mx = max(mx, x);
if (s - mx > t) {
s = x;
mx = x;
++d;
}
}
return d <= m;
};
while (left < right) {
int mid = (left + right) >> 1;
if (check(mid)) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
};
func minTime(time []int, m int) int {
right := 0
for _, x := range time {
right += x
}
return sort.Search(right, func(t int) bool {
s, mx := 0, 0
d := 1
for _, x := range time {
s += x
mx = max(mx, x)
if s-mx > t {
s, mx = x, x
d++
}
}
return d <= m
})
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
function minTime(time: number[], m: number): number {
let left = 0;
let right = time.reduce((a, b) => a + b);
const check = (t: number): boolean => {
let s = 0;
let mx = 0;
let d = 1;
for (const x of time) {
s += x;
mx = Math.max(mx, x);
if (s - mx > t) {
s = x;
mx = x;
d++;
}
}
return d <= m;
};
while (left < right) {
const mid = (left + right) >> 1;
if (check(mid)) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}