工作计划的最低难度【LC1335】
你需要制定一份
d
天的工作计划表。工作之间存在依赖,要想执行第i
项工作,你必须完成全部j
项工作(0 <= j < i
)。你每天 至少 需要完成一项任务。工作计划的总难度是这
d
天每一天的难度之和,而一天的工作难度是当天应该完成工作的最大难度。给你一个整数数组
jobDifficulty
和一个整数d
,分别代表工作难度和需要计划的天数。第i
项工作的难度是jobDifficulty[i]
。返回整个工作计划的 最小难度 。如果无法制定工作计划,则返回 -1 。
我和动态规划的关系就像是见过但是总是隐隐约约想不起来的陌生人
类似题目
dfs+记忆化
-
思路
题意可以转化为分割成d个子数组,使d个子数组的最大值之和最小。
-
寻找子问题:如果将后 [ k , n − 1 ] [k,n-1] [k,n−1]个任务在一天内完成,那么前面 [ 0 , k − 1 ] [0,k-1] [0,k−1]个任务需要在 d − 1 d-1 d−1天完成,因此找到了子问题,可以通过递归/动态规划来解决。(dfs+记忆化的形式最好理解)
-
定义dfs函数:定义 d f s ( i , j ) dfs(i,j) dfs(i,j)为在 i i i天完成 [ 0 , j ] [0,j] [0,j]个任务所需要的最小难度
-
递归入口:那么 d f s ( n − 1 , d ) dfs(n-1,d) dfs(n−1,d)即为答案
-
递归逻辑:
由于每一天都需要有工作任务,那么在决定第 i i i天的工作任务时,必须预留 i − 1 i-1 i−1个工作。因此在安排第 i i i天的工作任务时,我们枚举 [ i − 1 , j ] [i-1,j] [i−1,j]个任务,分割子数组,记录子数组中的最大值(当天的工作难度),然后递归到下一天,取最小值返回。
d f s ( i , j ) = m i n k = i − 1 j { d f s ( i − 1 , k − 1 ) + m a x p = k j ( j o b D i f f i c u l t y [ p ] ) } dfs(i,j)= min_{k= i-1}^{j}\{dfs(i-1,k-1)+max_{p=k}^{j}(jobDifficulty[p])\} dfs(i,j)=mink=i−1j{dfs(i−1,k−1)+maxp=kj(jobDifficulty[p])} -
递归边界:
只有一天时,必须完成所有任务
-
-
实现
(i可以整体缩小1)
class Solution { int[] jobDifficulty; int[][] memo; int res = Integer.MAX_VALUE; public int minDifficulty(int[] jobDifficulty, int d) { this.jobDifficulty = jobDifficulty; // 分割成d个子数组,使d个子数组的最大值之和最小 // dfs(i,j) j天完成[0,i]项工作所需要的最小难度 int n = jobDifficulty.length; if (n < d){ return -1; } memo = new int[d + 1][n]; for (int i = 0; i <= d; i++){ Arrays.fill(memo[i], -1); } return dfs(d, n - 1); } public int dfs(int i, int j){ // if (i < 0 || j <= 0) return 0; if (memo[i][j] != -1) return memo[i][j]; // 只有一天 if (i == 1){ int mx = 0; for (int k = 0; k <= j; k++){ mx = Math.max(mx, jobDifficulty[k]); } memo[i][j] = mx; return mx; } int res = Integer.MAX_VALUE; int mx = -1; // 枚举子数组范围 [i - 1, j] 留下i - 1个元素 for (int k = j; k >= i - 1; k--){ mx = Math.max(mx, jobDifficulty[k]); res = Math.min(res, mx + dfs(i - 1,k - 1)); } memo[i][j] = res; return res; } }
-
复杂度
- 时间复杂度: O ( n 2 d ) O(n^2d) O(n2d)
- 空间复杂度: O ( n d ) O(nd) O(nd)
-
递推
-
实现
class Solution { public int minDifficulty(int[] a, int d) { int n = a.length; if (n < d) return -1; var f = new int[d][n]; f[0][0] = a[0]; for (int i = 1; i < n; i++) f[0][i] = Math.max(f[0][i - 1], a[i]); for (int i = 1; i < d; i++) { for (int j = n - 1; j >= i; j--) { f[i][j] = Integer.MAX_VALUE; int mx = 0; for (int k = j; k >= i; k--) { mx = Math.max(mx, a[k]); // 从 a[k] 到 a[j] 的最大值 f[i][j] = Math.min(f[i][j], f[i - 1][k - 1] + mx); } } } return f[d - 1][n - 1]; } } 作者:灵茶山艾府 链接:https://leetcode.cn/problems/minimum-difficulty-of-a-job-schedule/solutions/2271631/jiao-ni-yi-bu-bu-si-kao-dong-tai-gui-hua-68nx/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
-
复杂度
- 时间复杂度: O ( n 2 d ) O(n^2d) O(n2d)
- 空间复杂度: O ( n d ) O(nd) O(nd)
-