思路一:排列组合
因为机器人走到底右下角,向下几步,向右几步都是固定的,
比如,m=3, n=2,我们只要向下 1 步,向右 2 步就一定能到达终点。走的步数就是:向右:m-1, 向下:n-1
所以总共的方案数:
# 排列组合, m = 3, n = 2,说明:向右走2步,向下走1步
# math.factorial() 求阶层
import math
def uniquePaths(self, m: int, n: int) -> int:
res = math.factorial(m+n-2)/(math.factorial(m-1)*math.factorial(n-1))
return res
思路二:动态规划
令 dp[i][j] 是到达 i, j 最多路径
动态方程:
注意,对于第一行 dp[0][j],或者第一列 dp[i][0],由于都是在边界,所以只能为 1, 其他位置的数值可以不固定,在这里为了方便我们都设为1.
时间复杂度:O(m*n)O(m∗n)
空间复杂度:O(m * n)O(m∗n)
#动态规划,动态方程(2种情况,):
# dp[i][j] = dp[i-1][j] + dp[i][j-1] (i!=1 and j !=1)
# dp[i][j] = 1 (i or j=1)
def uniquePaths2(self, m: int, n: int) -> int:
dp=[[1]*n for _ in range(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[-1][-1]
优化:因为我们每次只需要 dp[i-1][j],dp[i][j-1]
优化一:将一个表优化成了表中我们需要的两行
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
pre = [1] * n
cur = [1] * n
for i in range(1, m):
for j in range(1, n):
cur[j] = pre[j] + cur[j-1]
pre = cur[:]
return pre[-1]
优化二:在优化一的基础上,将两行优化成了我们需要的当前行,因为cur未更新前保存的结果是上一行的结果
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
cur = [1] * n
for i in range(1, m):
for j in range(1, n):
cur[j] += cur[j-1]
return cur[-1]
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
示例 1:
输入:
[ [0,0,0],
[0,1,0],
[0,0,0]]
输出: 2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
m=len(obstacleGrid)
n=len(obstacleGrid[0])
if m<1 or n<1: return 0
if obstacleGrid[0][0]==1: return 0
dp = [[0]*n for _ in range(m)]
for i in range(0,m):
for j in range(0,n):
if i==0 and j==0: dp[i][j]=1
elif i==0 and j!=0:
# 跳过obs==1的障碍物
if obstacleGrid[i][j]==0: dp[i][j]=dp[i][j-1]
elif i!=0 and j==0:
if obstacleGrid[i][j]==0: dp[i][j]=dp[i-1][j]
else:
if obstacleGrid[i][j]==0: dp[i][j]=dp[i-1][j]+dp[i][j-1]
return dp[-1][-1]
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。
def minPathSum(self, grid: List[List[int]]) -> int:
row,col=len(grid),len(grid[0])
min_value = grid[0][0]
dp = grid.copy()
for i in range(row):
for j in range(col):
if i==0 and j==0: continue
elif i==0 and j!=0: dp[i][j]=dp[i][j-1]+dp[i][j]
elif i!=0 and j==0: dp[i][j]=dp[i-1][j]+dp[i][j]
else:
dp[i][j]=min(dp[i-1][j],dp[i][j-1])+dp[i][j]
return dp[-1][-1]
晋升版:
一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。
我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。
骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。
有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);
其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球
(若房间里的值为正整数,则表示骑士将增加健康点数)。
为了尽快到达公主,骑士决定每次只向右或向下移动一步。
编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。
例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。
-2 (K) -3 3
-5 -10 1
10 30 -5 (P)
说明:
骑士的健康点数没有上限。
任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,
包括骑士进入的左上角房间以及公主被监禁的右下角房间。
思路: 要求哪个位置的值,最终就推向它
from typing import List
class Solution:
def calculateMinimumHP(self, dungeon: List[List[int]]) -> int:
r = len(dungeon)
l = len(dungeon[0])
for i in range(r-1,-1,-1):
for j in range(l-1, -1, -1):
if i==r-1 and j==l-1:
# dungeon[i][j] 表示到 [i][j] 节点时,只要保证有 dungeon[i][j] 滴血 就可以
dungeon[i][j]=max(1, 1-dungeon[i][j])
elif i==r-1 :
dungeon[i][j] = max(1, dungeon[i][j+1]-dungeon[i][j])
elif j==l-1:
dungeon[i][j] = max(1,dungeon[i+1][j]-dungeon[i][j])
else:
dp_min = min(dungeon[i+1][j], dungeon[i][j+1])
dungeon[i][j] = max(1, dp_min -dungeon[i][j])
return dungeon[0][0]
if __name__ == "__main__":
s = Solution()
nums= [[-2,-3,3],
[-5,-10,1],
[10,30,-5]]
r = s.calculateMinimumHP(nums)
print(r)