【每日一题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)
目录
相关文章
|
7月前
【每日一题Day312】LC2240买钢笔和铅笔的方案数 | 完全背包 数学
【每日一题Day312】LC2240买钢笔和铅笔的方案数 | 完全背包 数学
63 0
|
7月前
|
算法
【每日一题Day363】LC275H 指数Ⅱ | 二分答案
【每日一题Day363】LC275H 指数Ⅱ | 二分答案
62 0
|
6月前
|
算法 JavaScript 程序员
程序员必知:《程序设计与算法(二)算法基础》《第一周枚举》熄灯问题POJ
程序员必知:《程序设计与算法(二)算法基础》《第一周枚举》熄灯问题POJ
36 0
|
7月前
|
C语言
浙大版《C语言程序设计(第3版)》题目集 练习8-2 计算两数的和与差 (10分)
浙大版《C语言程序设计(第3版)》题目集 练习8-2 计算两数的和与差 (10分)
|
7月前
|
机器学习/深度学习 索引
字节3面真题,LeetCode上hard难度,极具启发性题解
字节3面真题,LeetCode上hard难度,极具启发性题解
|
7月前
【每日一题Day167】LC1000合并石头的最低成本 | 区间dp
【每日一题Day167】LC1000合并石头的最低成本 | 区间dp
60 1
【每日一题Day167】LC1000合并石头的最低成本 | 区间dp
|
7月前
|
机器学习/深度学习 算法 测试技术
【动态规划】【C++算法】1335 工作计划的最低难度
【动态规划】【C++算法】1335 工作计划的最低难度
|
7月前
【每日一题Day171】LC1125最小的必要团队 | 01背包 位运算
【每日一题Day171】LC1125最小的必要团队 | 01背包 位运算
48 1
|
7月前
【每日一题Day320】LC2651计算列车到站时间 | 数学
【每日一题Day320】LC2651计算列车到站时间 | 数学
49 0
|
7月前
【每日一题Day250】LC1253重构 2 行二进制矩阵 | 贪心模拟
【每日一题Day250】LC1253重构 2 行二进制矩阵 | 贪心模拟
54 0