2050. 并行课程 III
给你一个整数 n
,表示有 n
节课,课程编号从 1
到 n
。同时给你一个二维整数数组 relations
,其中 relations[j] = [prevCoursej, nextCoursej]
,表示课程 prevCoursej
必须在课程 nextCoursej
之前 完成(先修课的关系)。同时给你一个下标从 0 开始的整数数组 time
,其中 time[i]
表示完成第 (i+1)
门课程需要花费的 月份 数。
请你根据以下规则算出完成所有课程所需要的 最少 月份数:
请你返回完成所有课程所需要的 最少 月份数。
注意:测试数据保证一定可以完成所有课程(也就是先修课的关系构成一个有向无环图)。
示例 1:
输入:n = 3, relations = [[1,3],[2,3]], time = [3,2,5] 输出:8 解释:上图展示了输入数据所表示的先修关系图,以及完成每门课程需要花费的时间。 你可以在月份 0 同时开始课程 1 和 2 。 课程 1 花费 3 个月,课程 2 花费 2 个月。 所以,最早开始课程 3 的时间是月份 3 ,完成所有课程所需时间为 3 + 5 = 8 个月。
示例 2:
输入:n = 5, relations = [[1,5],[2,5],[3,5],[3,4],[4,5]], time = [1,2,3,4,5] 输出:12 解释:上图展示了输入数据所表示的先修关系图,以及完成每门课程需要花费的时间。 你可以在月份 0 同时开始课程 1 ,2 和 3 。 在月份 1,2 和 3 分别完成这三门课程。 课程 4 需在课程 3 之后开始,也就是 3 个月后。课程 4 在 3 + 4 = 7 月完成。 课程 5 需在课程 1,2,3 和 4 之后开始,也就是在 max(1,2,3,7) = 7 月开始。 所以完成所有课程所需的最少时间为 7 + 5 = 12 个月。
提示:
1 <= n <= 5 * 104
0 <= relations.length <= min(n * (n - 1) / 2, 5 * 104)
relations[j].length == 2
1 <= prevCoursej, nextCoursej <= n
prevCoursej != nextCoursej
[prevCoursej, nextCoursej]
都是 互不相同 的。time.length == n
1 <= time[i] <= 104
原站题解
javascript 解法, 执行用时: 224 ms, 内存消耗: 76.6 MB, 提交时间: 2023-07-28 14:37:43
/** * @param {number} n * @param {number[][]} relations * @param {number[]} time * @return {number} */ var minimumTime = function(n, relations, time) { let res = 0; let prev = Array(n + 1).fill(0); for (let i = 0; i <= n; i++) { prev[i] = []; } for (var relation of relations) { let x = relation[0], y = relation[1]; prev[y].push(x); } let memo = {}; for (let i = 1; i <= n; i++) { res = Math.max(res, dp(i, time, prev, memo)); } return res; }; function dp(i, time, prev, memo) { if (!memo[i]) { let cur = 0; for (let p of prev[i]) { cur = Math.max(cur, dp(p, time, prev, memo)); } cur += time[i - 1]; memo[i] = cur; } return memo[i]; }
golang 解法, 执行用时: 252 ms, 内存消耗: 24.3 MB, 提交时间: 2023-07-28 14:37:15
func minimumTime(n int, relations [][]int, time []int) int { res := 0 prev := make([][]int, n+1) for i := 0; i <= n; i++ { prev[i] = make([]int, 0) } for _, relation := range relations { x := relation[0] y := relation[1] prev[y] = append(prev[y], x) } memo := make(map[int]int) for i := 1; i <= n; i++ { res = max(res, dp(i, time, prev, memo)) } return res } func dp(i int, time []int, prev [][]int, memo map[int]int) int { if _, ok := memo[i]; !ok { cur := 0 for _, p := range prev[i] { cur = max(cur, dp(p, time, prev, memo)) } cur += time[i-1] memo[i] = cur } return memo[i] } func max(a, b int) int { if a > b { return a } return b }
cpp 解法, 执行用时: 408 ms, 内存消耗: 161.1 MB, 提交时间: 2023-07-28 14:37:02
class Solution { public: int minimumTime(int n, vector<vector<int>>& relations, vector<int>& time) { int mx = 0; vector<vector<int>> prev(n + 1); for (auto &relation : relations) { int x = relation[0], y = relation[1]; prev[y].emplace_back(x); } unordered_map<int, int> memo; function<int(int)> dp = [&](int i) -> int { if (!memo.count(i)) { int cur = 0; for (int p : prev[i]) { cur = max(cur, dp(p)); } cur += time[i - 1]; memo[i] = cur; } return memo[i]; }; for (int i = 1; i <= n; i++) { mx = max(mx, dp(i)); } return mx; } };
java 解法, 执行用时: 35 ms, 内存消耗: 77.6 MB, 提交时间: 2023-07-28 14:36:47
class Solution { public int minimumTime(int n, int[][] relations, int[] time) { int mx = 0; List<Integer>[] prev = new List[n + 1]; for (int i = 0; i <= n; i++) { prev[i] = new ArrayList<Integer>(); } for (int[] relation : relations) { int x = relation[0], y = relation[1]; prev[y].add(x); } Map<Integer, Integer> memo = new HashMap<Integer, Integer>(); for (int i = 1; i <= n; i++) { mx = Math.max(mx, dp(i, time, prev, memo)); } return mx; } public int dp(int i, int[] time, List<Integer>[] prev, Map<Integer, Integer> memo) { if (!memo.containsKey(i)) { int cur = 0; for (int p : prev[i]) { cur = Math.max(cur, dp(p, time, prev, memo)); } cur += time[i - 1]; memo.put(i, cur); } return memo.get(i); } }
python3 解法, 执行用时: 292 ms, 内存消耗: 89.3 MB, 提交时间: 2023-07-28 14:36:34
''' 记忆化搜索 构建临时先修课表prev, prev[y] 表示课程y所有的先修课 定义函数dp[i], 表示完成课程i所需最小月份 如果一门课有先修课时,dp[i]就是在它的所有先修课的最少完成月份的最大值的基础上加time[i-1] 如果没先修课,完成它的最小月份就是time[i-1] ''' class Solution: def minimumTime(self, n: int, relations: List[List[int]], time: List[int]) -> int: mx = 0 prev = [[] for _ in range(n + 1)] for x, y in relations: prev[y].append(x) # 先修课表 prev[y] 表示课程y所有的先修课 @lru_cache(None) def dp(i: int) -> int: # 完成课程i所需最小月份 cur = 0 for p in prev[i]: cur = max(cur, dp(p)) cur += time[i - 1] # 如果没先修课,完成最小月份就是time[i-1] return cur for i in range(1, n + 1): mx = max(mx, dp(i)) return mx