理论基础
509. 斐波那契数
70. 爬楼梯
746. 使用最小花费爬楼梯
62.不同路径
63. 不同路径 II
343. 整数拆分
96.不同的二叉搜索树
动态规划理论基础
动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。
所以动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的
对于动态规划问题,我将拆解为如下五步曲,这五步都搞清楚了,才能说把动态规划真的掌握了!
- 确定dp数组(dp table)以及下标的含义
- 确定递推公式
- dp数组如何初始化
- 确定遍历顺序
- 举例推导dp数组
509. 斐波那契数
class Solution: def fib(self, n: int) -> int: if n == 0: return 0 if n == 1: return 1 return self.fib(n-1)+self.fib(n-2)
70. 爬楼梯
记住要由递归公式推导出dp公式
class Solution: def climbStairs(self, n: int) -> int: if n == 1: return 1 if n == 2: return 2 dp = [0 for _ in range(n+1)] dp[1] = 1 dp[2] = 2 for i in range(3, n+1): dp[i] = dp[i-1] + dp[i-2] return dp[n]
746. 使用最小花费爬楼梯
class Solution: def minCostClimbingStairs(self, cost: List[int]) -> int: n = len(cost) if n == 1: return 0 if n == 2: return min(cost[0], cost[1]) dp = [0 for _ in range(n)] dp[0] = cost[0] dp[1] = cost[1] for i in range(2, n): dp[i] = cost[i] + min(dp[i-1], dp[i-2]) return min(dp[-1], dp[-2])
62.不同路径
class Solution: def uniquePaths(self, m: int, n: int) -> int: #M行 N列 if m == 1 or n == 1: return 1 dp = [[0 for _ in range(n)] for _ in range(m)] for i in range(n): dp[0][i] = 1 for j in range(m): dp[j][0] = 1 for j in range(1, m): for i in range(1,n): dp[j][i] = dp[j-1][i] + dp[j][i-1] return dp[-1][-1]
63. 不同路径 II
class Solution: def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int: n = len(obstacleGrid) #N行M列 m = len(obstacleGrid[0]) dp = [[0 for _ in range(m)]for _ in range(n)] if obstacleGrid[0][0] == 1: dp[0][0] = 0 else: dp[0][0] = 1 for i in range(1, m): if obstacleGrid[0][i] == 1: dp[0][i] = 0 else: dp[0][i] = dp[0][i-1] for j in range(1, n): if obstacleGrid[j][0] == 1: dp[j][0] = 0 else: dp[j][0] = dp[j-1][0] for j in range(1, n): for i in range(1, m): if obstacleGrid[j][i] == 1: dp[j][i] = 0 else: dp[j][i] = dp[j-1][i] + dp[j][i-1] return dp[-1][-1]
343. 整数拆分
注意遍历所有切割点的时候只用遍历【0,i//2+1】
class Solution: def integerBreak(self, n): if n <= 3: return 1 * (n - 1) # 对于n小于等于3的情况,返回1 * (n - 1) dp = [0] * (n + 1) # 创建一个大小为n+1的数组来存储最大乘积结果 dp[1] = 1 # 当n等于1时,最大乘积为1 dp[2] = 2 # 当n等于2时,最大乘积为2 dp[3] = 3 # 当n等于3时,最大乘积为3 # 从4开始计算,直到n for i in range(4, n + 1): # 遍历所有可能的切割点 for j in range(1, i // 2 + 1): # 计算切割点j和剩余部分(i - j)的乘积,并与之前的结果进行比较取较大值 dp[i] = max(dp[i], dp[i - j] * dp[j]) return dp[n] # 返回整数拆分的最大乘积结果
96.不同的二叉搜索树
相乘的思想
class Solution: def numTrees(self, n: int) -> int: if n == 1: return 1 dp = [0 for _ in range(n+1)] dp[0] = 1 dp[1] = 1 for i in range(2, n+1): for j in range(0,n): dp[i] += dp[j]*dp[i-j-1] return dp[n]