代码随想录动态规划part02|62.不同路径 、63.不同路径II 、343. 整数拆分、
- 62.不同路径
- 63.不同路径 II
- 343. 整数拆分 再看
- 本题思路并不容易想,一刷建议可以跳过。如果学有余力,可以看视频理解一波。
- 96.不同的二叉搜索树 跳过
62.不同路径
leetcode题目链接
代码随想录文档讲解
思路
:
若使用图论中的深度搜索、广度搜索,提交超时
- dp数组的含义:从[0,0]到[i,j]有多少种不同的路径
- dp[i][[j] = dp[i-1][j] + dp[i][j-1]
- 初始化,每一个状态都是从上面和左面得出来的,所以要初始化最上面一行和最左边一行:dp[0][j] = 1; dp[i][0] = 1
- 遍历顺序:从左向右,从上往下
伪代码(C++)
:
python代码
:
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
dp = [[1]*n]*m
for i in range(1, m):
for j in range(1, n):
dp[i][j] = dp[i-1][j]+dp[i][j-1]
return dp[m-1][n-1]
63.不同路径 II
leetcode题目链接
代码随想录文档讲解
思路
:
在不同路径题目中添加了障碍
- dp数组的含义:从[0,0]到达[i,j]有多少不同的路径
- 递推公式:dp[i][j] = dp[i-1][j] + dp[i][j-1] if obs[i][j] ==0
- 初始化:因为有了障碍,(i, j)如果就是障碍的话应该就保持初始状态(初始状态为0),并且之后的也全为0,初始化代码如下(for循环的终止条件添加一个obs判断)【如果起始位置和结束位置有障碍,那就是0种路径】
vector<vector<int>> dp(m, vector<int>(n, 0));
for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++) dp[i][0] = 1;
for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++) dp[0][j] = 1;
- 和
==注意:==数组初始化要这么写:dp = [[0] * n for _ in range(m)]
伪代码(C++)
:
python代码
:
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
# 可添加判断起始位置和终止位置是否为0的代码,降低复杂度
m, n = len(obstacleGrid), len(obstacleGrid[0])
# dp数组初始化
dp = [[0] * n for _ in range(m)]
# dp = [[0]*n]*m
for i in range(m):
if obstacleGrid[i][0] != 0:
break
dp[i][0] = 1
for j in range(n):
if obstacleGrid[0][j] != 0:
break
dp[0][j] = 1
for i in range(1, m):
for j in range(1, n):
if obstacleGrid[i][j] == 0:
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[m-1][n-1]
343. 整数拆分 再看
本题思路并不容易想,一刷建议可以跳过。如果学有余力,可以看视频理解一波。
leetcode题目链接
代码随想录文档讲解
思路
:
example:拆10
10 = 2 × 8 (10的状态依赖2和8的状态)
8 = 2 + 6 (8的状态依赖2和6的状态)
可使用动态规划来解决此问题:
- dp 的含义:dp[i] i拆分后最大的乘积为dp[i]
- 递推公式:dp[i] = max(dp[i], (i - j) * j, dp[i - j] * j)
i = j + (i-j), 再对i-j继续进行拆分 - 初始化 dp[0]=0; dp[2]=1
- 遍历顺序:
伪代码(C++)
:
python代码
:
class Solution:
# 假设对正整数 i 拆分出的第一个正整数是 j(1 <= j < i),则有以下两种方案:
# 1) 将 i 拆分成 j 和 i−j 的和,且 i−j 不再拆分成多个正整数,此时的乘积是 j * (i-j)
# 2) 将 i 拆分成 j 和 i−j 的和,且 i−j 继续拆分成多个正整数,此时的乘积是 j * dp[i-j]
def integerBreak(self, n):
dp = [0] * (n + 1) # 创建一个大小为n+1的数组来存储计算结果
dp[2] = 1 # 初始化dp[2]为1,因为当n=2时,只有一个切割方式1+1=2,乘积为1
# 从3开始计算,直到n
for i in range(3, n + 1):
# 遍历所有可能的切割点
for j in range(1, i // 2 + 1):
# 计算切割点j和剩余部分(i-j)的乘积,并与之前的结果进行比较取较大值
dp[i] = max(dp[i], (i - j) * j, dp[i - j] * j)
return dp[n] # 返回最终的计算结果
96.不同的二叉搜索树 跳过
leetcode题目链接
代码随想录文档讲解
思路
:
相当于爬楼梯题目的消费版
- dp数组的含义,到达i位置的花费为dp[i]
- dp[i]可由dp[i-1]跳1步或者dp[i-2]跳2步:dp[i] = min(dp[i-1] + cost[i-1] , dp[i-2] + cost[i-2])
- 初始化:dp[0]=0, dp[1]=0
- 每一个都是由前两个数组求得的,往前求
伪代码(C++)
:
python代码
:
class Solution:
def minCostClimbingStairs(self, cost: List[int]) -> int:
dp = [0] * (len(cost)+1)
for i in range(2, len(cost)+1):
dp[i] = min(dp[i-1] + cost[i-1], dp[i-2]+cost[i-2])
return dp[len(cost)]