一身转战三千里,一剑曾百万师。这篇文章主要讲述动态规划相关的知识,希望能为你提供帮助。
1. 斐波那契数列509. 斐波那契数
斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n >
1
给定 n ,请计算 F(n) 。示例 1:输入:n = 2
输出:1
解释:F(2) = F(1) + F(0) = 1 + 0 = 1
示例 2:输入:n = 3
输出:2
解释:F(3) = F(2) + F(1) = 1 + 1 = 2
示例 3:输入:n = 4
输出:3
解释:F(4) = F(3) + F(2) = 2 + 1 = 3
提示:0 <
= n <
= 30
题解:
class Solution:
def fib(self, n: int) ->
int:
if n == 0:
return 0if n == 1:
return 1dp = [0] * (n + 1)# 定义 dp 数组
dp[0] = 0# 初始化
dp[1] = 1for i in range(2, n+1):
dp[i] = dp[i - 1] + dp[i - 2]# 递推公式return dp[n]
2. 爬楼梯70. 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?示例 1:输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
示例 2:输入:n = 3
输出:3
解释:有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
提示:1 <
= n <
= 45
爬楼梯实质上也可以看作一个斐波拉契数列:
class Solution:
def climbStairs(self, n: int) ->
int:
dp = [0] * (n+1)
dp[0] = 1
dp[1] = 1
for i in range(2, n+1):
dp[i] = dp[i-1] + dp[i-2]return dp[n]
【动态规划】类似题目 剑指 Offer 10- II. 青蛙跳台阶问题:
class Solution:
def numWays(self, n: int) ->
int:
if n == 0 or n == 1:
return 1dp = [0] * (n + 1)
dp[0] = 1# 0 个台阶有 1 种 方法
dp[1] = 1# 1 个台阶有 1 种方法for i in range(2, n + 1):
dp[i] = dp[i - 1] + dp[i - 2]return dp[n] % 1000000007
3. 不同路径62. 不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。问总共有多少条不同的路径?示例 1:输入:m = 3, n = 7
输出:28
示例 2:输入:m = 3, n = 2
输出:3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 ->
向下 ->
向下
2. 向下 ->
向下 ->
向右
3. 向下 ->
向右 ->
向下
示例 3:输入:m = 7, n = 3
输出:28
示例 4:输入:m = 3, n = 3
输出:6
提示:1 <
= m, n <
= 100
题目数据保证答案小于等于 2 * 109
题解一:
class Solution:
def uniquePaths(self, m: int, n: int) ->
int:
dp = [[0 for i in range(n)] for j in range(m)]def diff_path(row, col):# 第一列的任意单元格,只有来自它上一个单元格过来的方法
for i in range(n):
dp[0][i] = 1# 第一行的任意单元格,只有来自它前一个单元格过来的一种方法
for j in range(m):
dp[j][0] = 1# 随意一个单元格有来自上或者左的两种路径,第一行、第一列已填充,不用继续填充
for i in range(1, row):
for j in range(1, col):
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]# 返回最后一个单元格的位置
return dp[row - 1][col - 1]return diff_path(m, n)
题解二:(更容易理解)
class Solution:
def uniquePaths(self, m: int, n: int) ->
int:
dp = [[0] * nfor i in range(m)]for row in range(m):
for col in range(n):
# 第一个格子只有一种方法
if row == 0 and col == 0:
dp[row][col] = 1
elif col == 0:
# 第一行的任意单元格,只有来自它前一个单元格过来的一种方法
dp[row][col] = dp[row-1][col]
elif row == 0:
# 第一列的任意单元格,只有来自它上一个单元格过来的方法
dp[row][col] = dp[row][col - 1]
else:
# 其他情况(中间):任意一个单元格有来自其左或上两个方向的机器人
dp[row][col] = dp[row - 1][col] + dp[row][col - 1]return dp[m - 1][n - 1]
4. 不同路径 II63. 不同路径 II
示例 1:输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
解释:3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 ->
向右 ->
向下 ->
向下
2. 向下 ->
向下 ->
向右 ->
向右示例 2:输入:obstacleGrid = [[0,1],[0,0]]
输出:1
提示:m == obstacleGrid.length
n == obstacleGrid[i].length
1 <
= m, n <
= 100
obstacleGrid[i][j] 为 0 或 1
题解:
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) ->
int:
row = len(obstacleGrid)
col = len(obstacleGrid[0])# 只有一个单元格,即一行一列时
if row == 1 and col == 1:
if obstacleGrid[0][0] == 1:
return 0
else:
return 1dp = [[0] * col for i in range(row)]for i in range(row):
for j in range(col):
# 遇到阻碍,就跳过当前循环
if obstacleGrid[i][j] == 1:
continueif i == 0 and j == 0:
dp[i][j] = 1
elif i == 0:
dp[i][j] = dp[i][j - 1]
elif j == 0:
dp[i][j] = dp[i - 1][j]
else:
dp[i][j] = dp[i][j - 1] + dp[i - 1][j]return dp[row - 1][col - 1]
5. 最小路径和64. 最小路径和
给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。说明:每次只能向下或者向右移动一步。示例 1:输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。
示例 2:输入:grid = [[1,2,3],[4,5,6]]
输出:12
提示:m == grid.length
n == grid[i].length
1 <
= m, n <
= 200
0 <
= grid[i][j] <
= 100
题解:
class Solution:
def minPathSum(self, grid: List[List[int]]) ->
int:
m, n = len(grid), len(grid[0])# 只有一个单元格时
if m == 1 and n == 1:
return grid[0][0]dp = [[0] * n for i in range(m)]for i in range(m):
for j in range(n):if i == 0:
# 第一行,和 = 当前单元格数字 + 前一个单元格数字
dp[i][j] = dp[i][j - 1] + grid[i][j]
elif j == 0:
# 第一列,和 = 当前单元格数字 + 上一个单元格数字
dp[i][j] = dp[i - 1][j] + grid[i][j]
else:
# 中间单元格,和 = 当前单元格数字 + 上一个和前一个单元格中最小的数字
dp[i][j] = min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j]return dp[m-1][n-1]
推荐阅读
- 2022年Java秋招面试,程序员求职必看的Dubbo面试题
- Elasticsearch 在地理信息空间索引的探索和演进
- Java常用类库
- 并发 JVM-JMM和底层实现原理
- MySQL中的读锁和写锁(InnoDb行锁表锁 MyISAM共享读锁 MyISAM独占写锁)
- d生成模板
- 并发-显示锁Lock和独占锁AQS(AbstractQueuedSynchronizer)
- d改进翻译
- 并发-原子操作和CAS(CompareAndSwep)