刷力扣学习动态规划[leetcode 63. 不同路径 II][leetcode 45. 跳跃游戏 II]
原题链接
https://leetcode-cn.com/problems/jump-game-ii/
https://leetcode-cn.com/problems/unique-paths-ii/
动态规划(Dynamic Programing,DP)和记忆化递归很像,都是把问题拆分成两个部分,当前问题和其余问题,只不过递归是先处理当前问题,然后处理剩下的问题,而动态规划是其余问题先处理,并且存储下来了。
因此动态规划的思路是,如果一个问题包含很多重复的子问题,那么可以先解决子问题并储存,那么处理其余问题的时候就可以调用以前的答案了。
处理dp的枚举思路可以直接直接遍历储存单位里的每一个元素,从这个角度来说dp比记忆化递归要简单。
下面是我写的两道动态规划的题目。
leetcode 63. 不同路径 II
创建step[m][n]
来表示每一个点上可能的情况数,用来储存上面所说的子问题答案,那么此时有
step[i][j] = step[i-1][j] + step[i][j-1]
,然后遍历即可
#63. 不同路径 II
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
m = len(obstacleGrid)
n = len(obstacleGrid[0])
step = [n * [None] for _ in range(m)]
for i in range(n):
if obstacleGrid[0][i] == 1:
break
else:
step[0][i] = 1
for i in range(m):
if obstacleGrid[i][0] == 1:
break
else:
step[i][0] = 1
obstacleGrid[0][0] = 0
if obstacleGrid[0][0] == 1 or obstacleGrid[m-1][n-1] == 1:
return 0
def func (m,n):
S = 0
if obstacleGrid[m-1][n] == 0 and step[m-1][n]:
S += step[m-1][n]
if obstacleGrid[m][n-1] == 0 and step[m][n-1]:
S += step[m][n-1]
if S:
return S
else:
return None
for i in range(1,m):
for j in range(1,n):
if obstacleGrid[i][j] == 1:
continue
if func(i,j):
step[i][j] = func(i,j)
if step[m-1][n-1]:
return step[m-1][n-1]
else:
return 0
leetcode 45. 跳跃游戏 IIzh
这儿我是用least[L]
来表示每一格的最少情况,然后不断刷新,但这题我要执行整整2s。。这题应该是要用贪心来做,不知道为什么被分到了dp里。。
#45. 跳跃游戏
def jump(self, nums: List[int]) -> int:
L = len(nums)
least = [None]*L
least[0]=0
step = 1
for i in range(L):
if least[i] != None:
step = least[i] + 1
for j in range(i+1,i+1+nums[i]):
if j>=L:
break
else:
if least[j] != None:
if least[j] > step:
least[j] = step
else:
least[j] = step
return step-1
还有一件事
动态规划仅仅是一种思想,而他本身又可以与各种算法结合起来,向上面跳跃问题可以与贪心算法结合,因此,这类题目可优化程度是非常大的。