343. 整数拆分:
代码思路
dp[i]就是答案(定义状态)。状态转移方程是max(i * (k-i), dp[i] * (k-i))。就是分成两种情况,第一种就是两个数相乘,第二种就是超过两个数相乘的情况。i * (k-i)是两个数相乘,dp[i] * (k-i)是超过两个数相乘的情况。但是重点还是先固定一个数,后面还有逐个逐个根据不同固定的数来比较一下。思路比较绕。
class Solution:
def integerBreak(self, n: int) -> int:
dp = [-1 for i in range(n+1)]
dp[0] = dp[1] = 0
k = 2
while k <= n:
for i in range(k):
temp = max(i * (k-i), dp[i] * (k-i))
if temp > dp[k]:
dp[k] = temp
k += 1
return dp[-1]
96. 不同的二叉搜索树:
代码思路
(首先是dp[i]即答案。
然后要懂得分解子问题,
基本状态转移方程就好推了。)
dp[i]即答案(定义状态),也就是i个节点构成的搜索树数量,倒推状态转移!倒推出来就差不多了。这题状态转移的发现要比较细心。其实就是分别拿一个节点作为根节点,左节点为子问题,右节点为子问题,左和右排列组合数相乘就ok了。所以说树类型的动态规划就是左子树和右子树变成了子问题,是不是以后碰到树+动归就好推了?其实动归就是递归中少了递的过程,只有归!!
class Solution:
def numTrees(self, n: int) -> int:
if n == 1:
return 1
dp = [0 for i in range(n+1)] # 代表由k个节点(数)组成的二叉搜索树数量
# for i in range(len(n)): # 轮流来作为根节点
i = 2
dp[1] = 1
while i <= n:
for j in range(1, i+1):
# j位置为根节点,dp[左边的节点个数]+dp[右边的节点个数]
if dp[j-1] == 0:
dp[i] += dp[i-j]
elif dp[i-j] == 0:
dp[i] += dp[j-1]
else:
dp[i] += dp[j-1]*dp[i-j]
i += 1
return dp[n]