最大休假天数

Submission

运行时间: 227 ms

内存: 16.8 MB

class Solution:
    # # dfs
    def maxVacationDays1(self, flights: List[List[int]], days: List[List[int]]) -> int:

        @cache
        def dfs(day, city):
            if day == len(days[0]):
                return 0

            res = dfs(day + 1, city) + days[city][day]
            for i in range(len(flights)):
                if not flights[city][i]:
                    continue

                res = max(res, dfs(day + 1, i) + days[i][day])

            return res
            

        return dfs(0, 0)



    # 动态规划
    def maxVacationDays(self, flights: List[List[int]], days: List[List[int]]) -> int:
        n, k = len(flights), len(days[0])
        
        # 记录可达城市信息
        dct = defaultdict(list)
        for i in range(n):
            for j in range(n):
                if flights[i][j]:
                    dct[i].append(j)
        
        # 初始化
        pre = [float('-inf')]*n
        pre[0] = 0
        for j in range(k):
            cur = pre[:]
            for i in range(n):
                # 状态转移,从城市i出发到达x
                for x in dct[i]:
                    if pre[i] + days[x][j] > cur[x]:
                        cur[x] = pre[i] + days[x][j]

                # 停留在城市i
                if pre[i] + days[i][j] > cur[i]:
                    cur[i] = pre[i] + days[i][j]

            pre = cur[:]

        return max(pre)

    

Explain

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

时间复杂度: O(n^2*k)

空间复杂度: O(n^2)

class Solution:
    # DFS解法
    def maxVacationDays1(self, flights: List[List[int]], days: List[List[int]]) -> int:
        @cache
        def dfs(day, city):
            # 递归出口:假期结束
            if day == len(days[0]):
                return 0
            
            # 停留在当前城市
            res = dfs(day + 1, city) + days[city][day]
            # 遍历所有可以到达的城市
            for i in range(len(flights)):
                if not flights[city][i]:
                    continue
                # 从可以到达的城市出发能获得的最大休假天数  
                res = max(res, dfs(day + 1, i) + days[i][day])

            return res
            
        return dfs(0, 0)

    # 动态规划解法
    def maxVacationDays(self, flights: List[List[int]], days: List[List[int]]) -> int:
        n, k = len(flights), len(days[0])
        
        # 记录可达城市信息
        dct = defaultdict(list)
        for i in range(n):
            for j in range(n):
                if flights[i][j]:
                    dct[i].append(j)
        
        # 初始状态:第0天只能从城市0出发
        pre = [float('-inf')]*n 
        pre[0] = 0
        # 遍历每一天
        for j in range(k):
            cur = pre[:]
            # 遍历每个城市
            for i in range(n):
                # 从城市i出发到达城市x
                for x in dct[i]:
                    if pre[i] + days[x][j] > cur[x]:
                        cur[x] = pre[i] + days[x][j]
                
                # 停留在城市i
                if pre[i] + days[i][j] > cur[i]:
                    cur[i] = pre[i] + days[i][j]
            
            pre = cur[:]

        return max(pre)

Explore

在DFS解法中,使用了Python的`@cache`装饰器来确保递归过程中不会重复计算相同的状态。这个装饰器自动保存每次函数调用的结果,并在后续遇到相同参数的调用时,直接返回已保存的结果。这样,每个状态 `(day, city)` 的结果只计算一次,避免了重复的计算,从而显著提高了算法的效率。

`@cache`装饰器是Python标准库中`functools`模块提供的一个功能,它能够自动地保存函数的调用结果及其对应的参数。在这种情况下,它保存了`dfs`函数的参数`day`和`city`以及函数返回的结果。当`dfs`函数再次被相同的参数`(day, city)`调用时,装饰器会直接返回之前保存的结果,而不是重新执行函数体。这样减少了重复计算,提高了程序的执行效率。

在动态规划解法中,`pre`数组用于保存上一天每个城市的最大休假天数,而`cur`数组则用于计算并存储当前天每个城市的最大休假天数。使用两个数组来交替更新的原因是,我们需要保留上一天的数据来计算当前天的值。如果只用一个数组,那么在更新当前天的值时就会覆盖掉上一天的数据,导致无法正确计算。通过交替使用`pre`和`cur`,我们可以在不丢失必要数据的情况下更新状态,同时也避免了额外的内存开销。

在动态规划的初始状态设置中,`pre[0]`被设为0因为假设只有城市0是在第0天可达的起点。其他城市的初始值设为负无穷大是为了表示在第0天,这些城市是不可达的。这种设置避免了在后续迭代中错误地考虑从不可达城市出发的情况。随着算法的进行,只有当某个城市通过某种路径变得可达时,其对应的值才会被更新为非负无穷大的值。这样确保了动态规划的正确性和有效性。