【每日一题Day208】LC1335工作计划的最低难度 | 动态规划

简介: 【每日一题Day208】LC1335工作计划的最低难度 | 动态规划

工作计划的最低难度【LC1335】

你需要制定一份 d 天的工作计划表。工作之间存在依赖,要想执行第 i 项工作,你必须完成全部 j 项工作( 0 <= j < i)。

你每天 至少 需要完成一项任务。工作计划的总难度是这 d 天每一天的难度之和,而一天的工作难度是当天应该完成工作的最大难度。

给你一个整数数组 jobDifficulty 和一个整数 d,分别代表工作难度和需要计划的天数。第 i 项工作的难度是 jobDifficulty[i]

返回整个工作计划的 最小难度 。如果无法制定工作计划,则返回 -1

我和动态规划的关系就像是见过但是总是隐隐约约想不起来的陌生人

类似题目

dfs+记忆化
  • 思路题意可以转化为分割成d个子数组,使d个子数组的最大值之和最小。
  • 寻找子问题:如果将后[k,n1]个任务在一天内完成,那么前面[0,k1]个任务需要在d1天完成,因此找到了子问题,可以通过递归/动态规划来解决。(dfs+记忆化的形式最好理解)
  • 定义dfs函数:定义dfs(i,j)为在i天完成[0,j]个任务所需要的最小难度
  • 递归入口:那么dfs(n1,d)即为答案
  • 递归逻辑

          由于每一天都需要有工作任务,那么在决定第i天的工作任务时,必须预留i1个工作。因此在安排第i天的工作任务时,我们枚举[i1,j]个任务,分割子数组,记录子数组中的最大值(当天的工作难度),然后递归到下一天,取最小值返回。

image.png

  • 递归边界

          只有一天时,必须完成所有任务

  • 实现

       

(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(n2d)
  • 空间复杂度: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(n2d)
  • 空间复杂度:O(nd)
目录
相关文章
|
2月前
【每日一题Day149】LC2389和有限的最长子序列 | 贪心+前缀和+二分查找
【每日一题Day149】LC2389和有限的最长子序列 | 贪心+前缀和+二分查找
27 0
|
2月前
|
算法
【每日一题Day363】LC275H 指数Ⅱ | 二分答案
【每日一题Day363】LC275H 指数Ⅱ | 二分答案
39 0
|
2月前
【每日一题Day243】LC1595连通两组点的最小成本 | 状态压缩dp
【每日一题Day243】LC1595连通两组点的最小成本 | 状态压缩dp
36 0
|
2月前
|
机器学习/深度学习 算法 测试技术
【动态规划】【C++算法】1335 工作计划的最低难度
【动态规划】【C++算法】1335 工作计划的最低难度
|
2月前
【每日一题Day167】LC1000合并石头的最低成本 | 区间dp
【每日一题Day167】LC1000合并石头的最低成本 | 区间dp
36 1
【每日一题Day167】LC1000合并石头的最低成本 | 区间dp
|
2月前
【每日一题Day171】LC1125最小的必要团队 | 01背包 位运算
【每日一题Day171】LC1125最小的必要团队 | 01背包 位运算
22 1
|
2月前
【每日一题Day330】LC337打家劫舍Ⅲ | 动态规划
【每日一题Day330】LC337打家劫舍Ⅲ | 动态规划
24 0
|
2月前
【每日一题Day224】LC2517礼盒的最大甜蜜度 | 二分答案
【每日一题Day224】LC2517礼盒的最大甜蜜度 | 二分答案
19 0
leetcode-每日一题1200. 最小绝对差
leetcode-每日一题1200. 最小绝对差
87 0
leetcode-每日一题1200. 最小绝对差
【每日一题Day62】LC1760袋子里最少数目的球 | 二分查找
首先,将题意转化为,当操作次数一定时,求出单个袋子里球的数目的最大值的最小值y yy,那么可以通过二分查找的方法找到最终的y yy,二分查找的下限为1,上限为数组nums中的最大值
107 0
【每日一题Day62】LC1760袋子里最少数目的球 | 二分查找