刷了动态规划的几个题,来总结下方法。
动态规划一般都有递推式,如果找到第n个和第n-1个之间的关系(或者还包含第n-2个),那么整个思路就会很清晰了,动态规划问题一般都是寻找最优路径类的问题。
leetcode 53. 最大子序和
用tem[i]来表示第i个点的最大子序和,那么tem[i]=max(tem[i-1]+nums[i],nums[i])
class Solution(object):
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
res=nums[0]
tem=nums[0]
for i in range(1,len(nums)):
tem=max(tem+nums[i],nums[i])
if tem>res:
res=tem
return res
leetcode 62. 不同路径
image.png
设定一个数组的dp[m][n] ,对于dp[i][j]表示到节点[i][j]有多少种不同的路径,dp[i][j]=dp[i-1][j]+dp[i][j-1],因为只能向下或者向右走
class Solution:
def uniquePaths(self, m, n):
"""
:type m: int
:type n: int
:rtype: int
"""
if m<=0 and n<=0:
return 0
dp=[[0]*n]*m
for i in range(m):
dp[i][0]=1
for i in range(n):
dp[0][i]=1
for i in range(1,m):
for j in range(1,n):
dp[i][j]=dp[i][j-1]+dp[i-1][j]
return dp[m-1][n-1]
leetcode 63. 不同路径 II
image.png
难度稍有增加,增加障碍物后,如果障碍物节点为[i][j],那么dp[i][j]=0,因为没有路可以到达这个节点。
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid):
"""
:type obstacleGrid: List[List[int]]
:rtype: int
"""
if len(obstacleGrid)==0:
return 0
m=len(obstacleGrid)
n=len(obstacleGrid[0])
dp = [[0]*n]*m
for i in range(0,m):
for j in range(0,n):
if obstacleGrid[i][j]==1:
dp[i][j]=0
else:
if i>0 and j==0:
dp[i][j] = dp[i-1][j]
elif i==0 and j>0:
dp[i][j] = dp[i][j-1]
elif i==0 and j==0:
dp[i][j]=1
else:
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[m-1][n-1]
leetcode 70. 爬楼梯
image.png
这个题的规律在于第n个台阶可以由第n-1个台阶爬一阶,还可以由第n-2阶台阶爬两阶得到,res[n]=res[n-1]+res[n-2]
class Solution(object):
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
a=1
b=2
res=0
if n==1:
return a
elif n==2:
return b
elif n>=3:
for i in range(3,n+1):
res=a+b
a=b
b=res
return res
leetcode 91. 解码方法
image.png
这个题我写的很复杂,先考虑了如果s的长度<=1的两种情况,然后考虑了len(s)>=2的时候,那么s[i]!=’0’的话,res[i]=res[i-1], 如果int(s[i-1:i+1])<=26,那么res[i]还有再加上res[i-2],也就是说把s[i]当做一个单独的数解析是一种情况,把s[i]和是s[i]和s[i-1]放在一起又是一种情况,就是要考虑这两种情况。如果s[i]==’0’,那么就看s[i-1]<=2,如果s[i]<=2,那么res[i]=res[i-2], 否则return 0,因为没有数字可以和0组合。所以把思路梳理成if … then…,就清晰了。
class Solution:
def numDecodings(self, s):
"""
:type s: str
:rtype: int
"""
if len(s)==0:
return 0
if len(s)==1:
if s=="0":
return 0
return 1 #在这句话之前都只是考虑长度小于1的情况
res=[0]*len(s)
if s[0]!="0":
res[0]=1
else:
return 0
if s[1]!="0":
res[1]=1
else:
res[1]=0
if int(s[:2])<=26 and int(s[:2])>0:
res[1]=res[1]+1
#在这之前准备好res[0] res[1]
for i in range(2,len(s)):
if s[i]!="0":
res[i]=res[i-1]
if s[i-1]!='0' and int(s[i-1:i+1])<=26:
res[i]+=res[i-2]
else:
if int(s[i-1:i+1])<=26 and int(s[i-1:i+1])>0:
res[i]=res[i-2]
else:
return 0
return res[-1]
leetcode 95 不同的二叉搜索树
image.png
实际上是求卡特兰数列,让1-n之间的数每个数都做一次根节点,左子树是比根节点小的数,右子树是比根节点大的数,以n=3为例,
Count[3] = Count[0]Count[2] (1为根的情况) + Count[1]Count[1] (2为根的情况) + Count[2]*Count[0] (3为根的情况)
本文来自 qqxx6661 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/qqxx6661/article/details/76285972?utm_source=copy
class Solution:
def numTrees(self, n):
"""
:type n: int
:rtype: int
"""
dp=[1,1,2]#指的是dp[0] dp[1] dp[2]
if n<=2:
return dp[n]
dp+=[0 for i in range(n-2)]
for i in range(3,n+1):
for j in range(0,i):
dp[i]+=dp[j]*dp[i-1-j]
return dp[n]
leetcode 94:
请看这篇解答吧,我一开始没啥思路https://blog.csdn.net/fuxuemingzhu/article/details/80778651
image.png
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def generateTrees(self, n):
"""
:type n: int
:rtype: List[TreeNode]
"""
if n==0:
return []
return self.dfs(1,n)
def dfs(self,s,e):
if s>e:
return [None]
res=[]
for tem in range(s,e+1):
left=self.dfs(s,tem-1)
right=self.dfs(tem+1,e)
for i in left:
for j in right:
root=TreeNode(tem)
root.left=i
root.right=j
res.append(root)
return res
怕什么真理无穷,进一寸有一寸的欢喜。—–胡适