leetcode
leetcode 501 ~ 550
最大休假天数

最大休假天数

难度:

标签:

题目描述

代码结果

运行时间: 227 ms, 内存: 16.8 MB


/*
题目思路:
1. 使用动态规划结合Java Stream API来解决最大休假天数的问题。
2. 定义一个二维数组dp,其中dp[i][j]表示在第i周到城市j所能获得的最大休假天数。
3. 初始化第一周的休假天数。
4. 从第二周开始,更新dp数组,根据上一周的结果计算当前周的最大休假天数。
5. 最终,从dp数组的最后一行中找到最大的休假天数。
*/
 
import java.util.Arrays;
 
public class MaxVacationDaysStream {
    public int maxVacationDays(int[][] flights, int[][] days) {
        int N = flights.length; // 城市数量
        int K = days[0].length; // 周数
        int[][] dp = new int[K][N];
        // 初始化dp数组
        for (int i = 0; i < N; i++) {
            dp[0][i] = (flights[0][i] == 1 || i == 0) ? days[i][0] : -1;
        }
        // 计算从第二周到第K周的最大休假天数
        for (int week = 1; week < K; week++) {
            int[] temp = new int[N];
            Arrays.fill(temp, -1);
            for (int city = 0; city < N; city++) {
                int finalCity = city;
                temp[city] = Arrays.stream(dp[week - 1]).flatMap(prevDays -> {
                    int prevCity = Arrays.asList(dp[week - 1]).indexOf(prevDays);
                    return (prevDays != -1 && (flights[prevCity][finalCity] == 1 || finalCity == prevCity))
                        ? Arrays.stream(new int[]{prevDays + days[finalCity][week]})
                        : Arrays.stream(new int[]{-1});
                }).max().orElse(-1);
            }
            dp[week] = temp;
        }
        // 找到最后一周的最大休假天数
        return Arrays.stream(dp[K - 1]).max().orElse(0);
    }
}
 

解释

方法:

该题解提供了两种解法。第一种是深度优先搜索(DFS)的递归解法,通过记忆化搜索避免重复计算。从第0天开始,对每个城市进行DFS,计算从该城市出发能获得的最大休假天数。第二种是动态规划解法,用两个数组pre和cur分别记录上一天和当前天每个城市能获得的最大休假天数。对于每一天,遍历所有城市,更新cur数组,考虑从上一天能到达的城市出发或停留在当前城市的休假天数,取最大值。最后返回最后一天各城市的最大休假数。

时间复杂度:

O(n^2*k)

空间复杂度:

O(n^2)

代码细节讲解

🦆
在DFS解法中,如何确保递归的过程中不会重复计算相同的状态?
在DFS解法中,使用了Python的`@cache`装饰器来确保递归过程中不会重复计算相同的状态。这个装饰器自动保存每次函数调用的结果,并在后续遇到相同参数的调用时,直接返回已保存的结果。这样,每个状态 `(day, city)` 的结果只计算一次,避免了重复的计算,从而显著提高了算法的效率。
🦆
DFS解法中使用了@cache装饰器,这个装饰器是如何影响函数的执行的?它保存了哪些数据?
`@cache`装饰器是Python标准库中`functools`模块提供的一个功能,它能够自动地保存函数的调用结果及其对应的参数。在这种情况下,它保存了`dfs`函数的参数`day`和`city`以及函数返回的结果。当`dfs`函数再次被相同的参数`(day, city)`调用时,装饰器会直接返回之前保存的结果,而不是重新执行函数体。这样减少了重复计算,提高了程序的执行效率。
🦆
动态规划解法中,pre数组和cur数组的作用具体是什么?为什么需要两个数组来交替更新?
在动态规划解法中,`pre`数组用于保存上一天每个城市的最大休假天数,而`cur`数组则用于计算并存储当前天每个城市的最大休假天数。使用两个数组来交替更新的原因是,我们需要保留上一天的数据来计算当前天的值。如果只用一个数组,那么在更新当前天的值时就会覆盖掉上一天的数据,导致无法正确计算。通过交替使用`pre`和`cur`,我们可以在不丢失必要数据的情况下更新状态,同时也避免了额外的内存开销。
🦆
在动态规划解法的迭代过程中,为什么初始状态pre数组中除了pre[0]为0之外,其他都设置为负无穷?
在动态规划的初始状态设置中,`pre[0]`被设为0因为假设只有城市0是在第0天可达的起点。其他城市的初始值设为负无穷大是为了表示在第0天,这些城市是不可达的。这种设置避免了在后续迭代中错误地考虑从不可达城市出发的情况。随着算法的进行,只有当某个城市通过某种路径变得可达时,其对应的值才会被更新为非负无穷大的值。这样确保了动态规划的正确性和有效性。

相关问题

K 站中转内最便宜的航班

n 个城市通过一些航班连接。给你一个数组 flights ,其中 flights[i] = [fromi, toi, pricei] ,表示该航班都从城市 fromi 开始,以价格 pricei 抵达 toi

现在给定所有的城市和航班,以及出发城市 src 和目的地 dst,你的任务是找到出一条最多经过 k 站中转的路线,使得从 srcdst价格最便宜 ,并返回该价格。 如果不存在这样的路线,则输出 -1

 

示例 1:

输入: 
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 1
输出: 200
解释: 
城市航班图如下


从城市 0 到城市 2 在 1 站中转以内的最便宜价格是 200,如图中红色所示。

示例 2:

输入: 
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 0
输出: 500
解释: 
城市航班图如下


从城市 0 到城市 2 在 0 站中转以内的最便宜价格是 500,如图中蓝色所示。

 

提示:

  • 1 <= n <= 100
  • 0 <= flights.length <= (n * (n - 1) / 2)
  • flights[i].length == 3
  • 0 <= fromi, toi < n
  • fromi != toi
  • 1 <= pricei <= 104
  • 航班没有重复,且不存在自环
  • 0 <= src, dst, k < n
  • src != dst