动态规划专题讲解
动态规划思路:
明确 base case -> 明确「状态」-> 明确「选择」 -> 定义 dp 数组/函数的含义。
代码改进方向:
暴力递归 -> 带备忘录的递归-> dp数组迭代
斐波那契数
斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。
动态规划dp数组:
class Solution:
def fib(self, n: int) -> int:
if n <= 1:
return n
dp = [0 for _ in range(n + 1)]
dp[1] = 1
dp[2] = 1
for i in range(3, n + 1):
dp[i] = dp[i-1] + dp[i-2]
return dp[-1]
优化存储:
class Solution:
def fib(self, n: int) -> int:
if n <= 1:
return n
pre = cur = 1
for i in range(2, n):
pre, cur = cur, pre + cur
return cur
零钱兑换
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
你可以认为每种硬币的数量是无限的。
dp数组:
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
dp = [ amount + 1 for j in range(amount + 1)]
dp[0] = 0
coins.sort()
for i in range(1, amount + 1):
for coin in coins:
if coin > i:
break
dp[i] = min(dp[i], dp[i-coin]+1)
return dp[-1] if dp[-1] != amount + 1 else -1
改进, 使用amount + 1 初始化相当于inf,coins数组排序,可以在循环中提前结束,时间复杂度降低。dp数组预留0位置为0,表示0值对应没有硬币,最后加个判断,判断是否为为inf。