灵神题单_动态规划_入门DP_1.爬楼梯系列

DP三部曲解释
设计状态 f ( i ) f(i) f(i) 表示从 0 0 0 i i i 的方案数
递推公式 f ( i ) = f ( i − 1 ) + f ( i − 2 ) f(i) = f(i -1) + f(i -2) f(i)=f(i1)+f(i2)
边界条件 i = 0 i = 0 i=0 i = 1 i = 1 i=1 f ( i ) f(i) f(i) = 1
最终答案 f ( n ) f(n) f(n)

方法1:DFS
时间复杂度: O ( 2 n ) O(2^n) O(2n)
空间复杂度: O ( n ) O(n) O(n)

class Solution:
    def climbStairs(self, n: int) -> int:
        def dfs(i):
            if i == 0 or i == 1:
                return 1
            return dfs(i - 1) + dfs( i - 2)
        return dfs(n)

方法2:记忆化DFS
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)

class Solution:
    def climbStairs(self, n: int) -> int:
        @cache
        def dfs(i):
            if i == 0 or i == 1:
                return 1
            return dfs(i - 1) + dfs( i - 2)
        return dfs(n)

方法3:递推
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)

class Solution:
    def climbStairs(self, n: int) -> int:
        dp = [0] * (n + 1)
        dp[0] = dp[1] = 1
        for i in range(2, n + 1):
            dp[i] = dp[i - 1] + dp[i - 2]
        return dp[n]

方法4:空间优化递推
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( 1 ) O(1) O(1)

class Solution:
    def climbStairs(self, n: int) -> int:
        f0, f1 = 1, 1
        for i in range(2, n + 1):
            f0, f1 = f1, f0 + f1
        return f1
DP三部曲解释
设计状态 f ( i ) f(i) f(i) 表示从 0 0 0 i i i 的最小花费
递推公式 f ( i ) = m i n ( f ( i − 1 ) , f ( i − 2 ) ) + c o s t [ i ] f(i) = min(f(i -1), f(i -2)) + cost[i] f(i)=min(f(i1),f(i2))+cost[i]
边界条件 f ( 0 ) = c o s t [ 0 ] f(0) = cost[0] f(0)=cost[0] f ( 1 ) = c o s t [ 1 ] f(1) = cost[1] f(1)=cost[1]
最终答案 m i n ( f ( n − 2 ) , f ( n − 1 ) ) min(f(n-2), f(n-1)) min(f(n2),f(n1)) 其中 n n n 表示数组长度

方法1:记忆化DFS(递推公式与设计不一样)
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)

class Solution:
    def minCostClimbingStairs(self, cost: List[int]) -> int:
        @cache
        def dfs(i):
            if i == 0 or i == 1:
                return 0
            return min(dfs(i - 1) + cost[i - 1], dfs(i - 2) + cost[i - 2])
        return dfs(len(cost))

方法2:空间优化递推
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( 1 ) O(1) O(1)

class Solution:
    def minCostClimbingStairs(self, cost: List[int]) -> int:
        n = len(cost); f0, f1 = cost[0], cost[1]
        for i in range(2, n):
            f0, f1 = f1, min(f0, f1) + cost[i]
        return min(f0, f1)
DP三部曲解释
设计状态 f ( i ) f(i) f(i) 表示和为 i i i 的方案数
递推公式 f ( i ) = ∑ j = 0 n − 1 f ( i − n u m s [ j ] ) f(i) =\sum_{j=0}^{n-1} f(i - nums[j]) f(i)=j=0n1f(inums[j]) 其中 n n n 表示数组长度
边界条件 f ( 0 ) = 1 f(0) = 1 f(0)=1 f ( 负数 ) = 0 f(负数) = 0 f(负数)=0
最终答案 f ( t a r g e t ) f(target) f(target)

方法1:自顶向下记忆化DFS
时间复杂度: O ( n × t a r g e t ) O(n \times target) O(n×target)
空间复杂度: O ( t a r g e t ) O(target) O(target)

class Solution:
    def combinationSum4(self, nums: List[int], target: int) -> int:
        @cache
        def dfs(i):
            if i == 0:
                return 1
            if i < 0:
                return 0
            ans = 0
            for x in nums:
                ans += dfs(i - x)
            return ans
        return dfs(target)

方法2:自底向上记忆化DFS
时间复杂度: O ( n × t a r g e t ) O(n \times target) O(n×target)
空间复杂度: O ( t a r g e t ) O(target) O(target)

class Solution:
    def combinationSum4(self, nums: List[int], target: int) -> int:
        @cache
        def dfs(val):            
            if val > target:
                return 0            
            if val == target:
                return 1
            ans = 0
            for x in nums:
                ans += dfs(val + x)
            return ans
        return dfs(0)

方法3:递推
时间复杂度: O ( n × t a r g e t ) O(n \times target) O(n×target)
空间复杂度: O ( t a r g e t ) O(target) O(target)

class Solution:
    def combinationSum4(self, nums: List[int], target: int) -> int:
        dp = [1] + [0] * target
        for i in range(1, target + 1):
            for x in nums:
                if i >= x:
                    dp[i] += dp[i - x]
        return dp[target]
DP三部曲解释
设计状态 f ( i ) f(i) f(i) 表示长度为 i i i 的方案数
递推公式 f ( i ) = f ( i − z e r o ) + f ( i − o n e ) f(i) = f(i - zero) + f(i - one) f(i)=f(izero)+f(ione)
边界条件 f ( 0 ) = 1 f(0) = 1 f(0)=1 f ( 负数 ) = 0 f(负数) = 0 f(负数)=0
最终答案 ∑ i = l o w h i g h f ( i ) \sum_{i=low}^{high} f(i) i=lowhighf(i)

方法1:递推
时间复杂度: O ( h i g h ) O(high) O(high)
空间复杂度: O ( h i g h ) O(high) O(high)

class Solution:
    def countGoodStrings(self, low: int, high: int, zero: int, one: int) -> int:
        MOD = 10 ** 9 + 7; dp = [1] + [0] * high
        for i in range(1, high + 1):
            dp[i] = dp[i - zero] if i >= zero else 0
            dp[i] += dp[i - one] if i >= one else 0
            dp[i] %= MOD
        return sum(dp[low:]) % MOD
N = 10 ** 5; MOD = 10 ** 9 + 7
f = [1, 1, 2] + [0] * N
for i in range(3, N + 1):
    f[i] = (f[i - 1] + f[i - 2] + f[i - 3]) % MOD

g = [1, 1, 2, 4] + [0] * N
for i in range(4, N + 1):
    g[i] = (g[i - 1] + g[i - 2] + g[i - 3] + g[i - 4]) % MOD
    
class Solution:
    def countTexts(self, pressedKeys: str) -> int:
        pressedKeys += '#'
        ch = pressedKeys[0]; cnt = 0; ans = 1
        for s in pressedKeys:
            if s == ch:
                cnt += 1
            else:
                if ch == '7' or ch == '9':
                    ans *= g[cnt]
                else:
                    ans *= f[cnt]
                ans %= MOD
                ch = s; cnt = 1
        return ans % MOD

方法2:分组(使用groupby函数) + 递推(和LeetCode 377.组合总和 Ⅳ类似) + 乘法原理
时间复杂度: O ( N ) O(N) O(N)
空间复杂度: O ( N ) O(N) O(N)

N = 10 ** 5; MOD = 10 ** 9 + 7
f = [1, 1, 2] + [0] * N
for i in range(3, N + 1):
    f[i] = (f[i - 1] + f[i - 2] + f[i - 3]) % MOD

g = [1, 1, 2, 4] + [0] * N
for i in range(4, N + 1):
    g[i] = (g[i - 1] + g[i - 2] + g[i - 3] + g[i - 4]) % MOD
    
class Solution:
    def countTexts(self, pressedKeys: str) -> int:
        from itertools import groupby
        ans = 1
        for ch, idxs in groupby(pressedKeys):
            L = len(list(idxs))
            if ch == '7' or ch == '9':
                ans *= g[L]
            else:
                ans *= f[L]
            ans %= MOD
        return ans
  • 15
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胆怯与勇敢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值