1.代码随想录Day62.代码随想录Day7|哈希表part02 3.代码随想录Day8|字符串4.代码随想录Day9| 5.代码随想录Day10|栈与队列6.代码随想录Day11|栈和队列7.代码随想录12|栈和队列8.代码随想录Day14|二叉树9.代码随想录Day15|二叉树10.代码随想录Day15|二叉树III11.代码随想录算法训练营14期 Day112.代码随想录训练营day2| leetcode977, 209,5913.代码随想录day16| 二叉树(四)14.代码随想录Day17|二叉树(五)15.代码随想录Day19|二叉树(六)16.代码随想录|二叉树(最后一章)17.代码随想录|二叉树总结18.代码随想录Day23|回溯算法19.代码随想录Day24|回溯算法+JAVA大作战20.代码随想录|回溯算法(终回)21.代码随想录Day30|贪心122.代码随想录Day32|贪心II23.代码随想录|贪心III24.代码随想录|贪心(终章)
25.代码随想录|动态规划
26.代码随想录|动态规划-01背包问题27.代码随想录|完全背包28.代码随想录|打家劫舍问题29.代码随想录|各种买卖股票问题30.代码随想录|动态规划 - 子序列系列31.代码随想录|动态规划32.代码随想录|动态规划-编辑距离33.代码随想录|动态规划(终章)34.代码随想录|单调栈 理论基础
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]
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】