动态规划 Dynamic Programming
“Simplifying a complicated problem by breaking it down into simpler subproblems” (in a recursive manner)
Divide & Conquer + Optimal substructure
关键点:
动态规划和递归或者分治没有根本上的区别(关键看有无最优子结构)
共性:找到重复子问题
差异性:最优子结构、中途可以淘汰次优解
动态规划 关键点:
1、最优子结构 opt[n] = best_of(opt[n-1],opt[n-2],…)
2、储存中间状态:opt[i]
3、递推公式(美其名曰:状态转移方程或者DP方程)
Fib:opt[i] = opt[n-1] + opt[n-2]
二维路径:opt[i,j] = opt[i+1][j] + opt[i][j+1] (且判断a[i,j]是否为空地)
剑指offer 98.路径的数目
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
输入:m = 3, n = 7
输出:28
解法一:动态规划,写出状态转移方程dp[i][j] = dp[i-1][j] + dp[i][j-1]
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
dp = [[0]* n for _ in range(m)]
# 将第0行第0列都初始化为1
for j in range(n):
dp[0][j] = 1
for i in range(m):
dp[i][0] = 1
# 两层循环遍历
for j in range(1,n):
for i in range(1,m):
dp[i][j] = dp[i][j-1] + dp[i-1][j]
return dp[m-1][n-1]
解法二:排列组合
这道题只能向右或者向左,说明只会有两种情况
那么分析这道题
1、向右的数量和向下的数量的和是一定的
2、向右和向下的没什么区别
1)如果我们边长为 m,n,则有(m - 1)个向右 , (n - 1 )个向下得到最终的结果
2)转化为 有 (m-1) 个向下 ,我们需要把( n - 1)个向右插入向下中,
注:因为m -1 有头尾 则有m个间隙
3)转化为 高中做过的竞赛题 (n - 1) 个乒乓球 插入到编号为 (1到m) m个洞中,洞可以为空
4)转化为 有(n+m - 1) 个乒乓球 我们需要把它放入m个洞中,每个洞最少放一个
5)转化为 有 (n+m - 2) 个乒乓球间隙,放入 m -1 个挡板,把球分成m份,每份不能为空
那么得到我们最终的公式
代码:
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
res = 1
x = n
y = 1
while x <= n + m -2:
res = res * x // y
x += 1
y += 1
return res