题目
437 · 书籍复印
算法
中等
通过率
40%
题目
题解
笔记
讨论
排名
描述
给定n本书,第i本书有pages[i]页。有k个人来抄这些书。
这些书排成一行,每个人都可以索取连续一段的书。例如,一个抄书人可以连续地将书从第i册复制到第j册,但是他不能复制第1册、第2册和第4册(没有第3册)。
他们在同一时间开始抄书,每抄一页书都要花1分钟。为了让最慢的抄书人能在最早的时间完成书的分配,最好的策略是什么?
请返回最慢抄书人花费的最短时间。
背完这套刷题模板,真的不一样!
北大学霸令狐冲15年刷题经验总结的《算法小抄模板Cheat Sheet》助你上岸!
微信添加【jiuzhang0607】备注【小抄】领取
书籍页数总和小于等于2147483647
样例
样例 1:
输入: pages = [3, 2, 4], k = 2
输出: 5
解释: 第一个人复印前两本书, 耗时 5 分钟. 第二个人复印第三本书, 耗时 4 分钟.
样例 2:
输入: pages = [3, 2, 4], k = 3
输出: 4
解释: 三个人各复印一本书.
挑战
时间复杂度 O(nk)
方法1:动态规划
public int copyBooks(int[] pages, int k) {
int n = pages.length;
int[][] f = new int[k + 1][n + 1];
int INF = Integer.MAX_VALUE;
Arrays.fill(f[0], INF);
f[0][0] = 0;
for (int t = 1; t <= k; t++) {
f[t][0] = 0;
for (int i = 1; i <= n; i++) {
f[t][i] = INF;
int sum = 0;
for (int j = i; j >= 0; j--) {
f[t][i] = Math.min(f[t][i], Math.max(f[t - 1][j], sum));
if (j > 0) sum += pages[j - 1];
}
}
}
return f[k][n];
}
方法2:二分
public int copyBooks(int[] pages, int k) {
int maxx = 0, tot = 0;
for (int x : pages) {
maxx = Math.max(maxx, x);
tot += x;
}
int start = maxx, end = tot;
while (start + 1 < end) {
int mid = start + (end - start) / 2;
if (countWorkers(pages, mid) <= k) {
end = mid;
} else {
start = mid + 1;
}
}
if (countWorkers(pages, start) <= k) return start;
return end;
}
public int countWorkers(int[] pages, int t) {
int sum = 0;
int count = 0;
for (int x : pages) {
if (x + sum > t) {
sum = x;
count++;
} else {
sum += x;
}
}
count++;
return count;
}