0329
of10.斐波那契数列
一道很基本的动态规划题目,但确实很能展现出应注意的点
比如直接使用递归本题会超出时间的限制
class Solution:
def fib(self, n: int) -> int:
if n < 2:
return n
else:
# dp= [0] * (n+1)
dp = [i for i in range(n+1)]
dp[1] = dp[2] =1
for i in range(3, n+1):
dp[i] = dp[i-2] + dp[i-1]
return dp[n] % 1000000007
使用动态规划可以很明显的减小计算复杂度,因为dp数组包含有记录的功能
746.最小花费爬楼梯
class Solution:
def minCostClimbingStairs(self, cost: List[int]) -> int:
dp = [0] * (len(cost)) # 2.1初始化dp数组,本题对初始化没有什么特殊要求,直接初始化为0即可
dp[0] = cost[0] # 2.2前两个楼梯要赋值初始化
dp[1] = cost[1] # 2.3前两个楼梯要赋值初始化
for i in range(2, len(cost)): # 4.动态规划如何遍历
dp[i] = min(dp[i-1], dp[i-2]) + cost[i] # 3.递推公式
return min(dp[len(cost)-1], dp[len(cost)-2]) # 1.确定dp数组的准确含义
开始体现出动态规划的一些基本点:确定dp数组含义,确定递推公式(即如何得到dp[i])、如何初始化dp数组、如何从初始化处开始向下遍历dp数组(与递推公式不同)。
dp[i]的定义是:到达第i个台阶所花费的最少体力为dp[i]
递推公式为:dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i],即由前1个或者前2个状态中的一个转化而来,选择较小的那个转化过来。cost[i]代表上这层楼那就一定会花费这层楼所需的代价。
初始化dp数组:自然是dp[0] = cost[0]; dp[1] = cost[1]
确定遍历过程:最后一步,递归公式有了,初始化有了,如何遍历呢?本题的遍历顺序其实比较简单,简单到可能忽略了思考这一步直接就把代码写出来了。因为是模拟台阶,而且dp[i]又dp[i-1]dp[i-2]推出,所以是从前到后遍历cost数组就可以了。
62.不同路径
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
dp = [[0 for i in range(n)] for j in range(m)] # 初始化dp数组
for i in range(m): # 所有行的第一个元素为1
dp[i][0] = 1
for j in range(n):
dp[0][j] = 1 # 所有列的第一个元素为1
for i in range(1, m): # dp数组的遍历过程
for j in range(1, n):
dp[i][j] = dp[i-1][j] + dp[i][j-1] # dp递推公式
return dp[m-1][n-1] # 返回最后一个位置元素即是结果
开始接触机器人路径问题了,这是我之前很头疼的一类问题,确实也是最能体现动态规划思想的问题之一(还有背包问题)
机器人的路径问题是一个在二维范围内思考的问题
dp数组含义:直接从题目入手,dp[i][j]是从(0, 0)位置出发到(i, j)位置位置,有dp[i][j]条不同的路径
递推公式:dp[i][j]可以从两个方向推导过来,自然是dp[i][j] = dp[i-1][j] + dp[i][j-1]
dp数组初始化:dp[i][0] = dp[0][j] = 1,这其中包括了dp[0][0]的初始化为1,以及边界行和边界列一定为
确定遍历顺序:这里要看一下递归公式dp[i][j] = dp[i - 1][j] + dp[i][j - 1],dp[i][j]都是从其上方和左方推导而来,那么从左到右一层一层遍历就可以了。这样就可以保证推导dp[i][j]的时候,dp[i - 1][j] 和 dp[i][j - 1]一定是有数值的。