目录
题目链接:343. 整数拆分
思路
①dp数组,分拆数字i,可以得到最大的乘积为dp[i]
②递推公式,dp[i] = max({dp[i], (i - j) * j, dp[i - j] * j}),j从1开始,(i - j) * j是将i拆分成这两个数进行相乘,dp[i - j] * j是i-j拆分的最大乘积再乘以j,取这三个数的最大值即可
③dp数组初始化,按照dp数组定义以及题意,不对0和1进行初始化,直接初始化dp[2]=1
④遍历顺序,双循环,外层i从3开始,内层j从1开始,进行拆分
⑤推到dp数组
代码
class Solution {
public:
int integerBreak(int n) {
if (n == 2)
return 1;
vector<int> dp(n + 1, 0); // 定义dp数组
dp[2] = 1; // dp数组初始化
// 对n进行拆分,只可能拆分成比n小的数字,因此i只到n-1
for (int i = 3; i <= n; i++) {
for (int j = 1; j < i - 1; j++) {
//拆分后,取乘积最大值
dp[i] = max(dp[i], max((i - j) * j, (dp[i - j] * j)));
}
}
return dp[n];
}
};
题目链接:96.不同的二叉搜索树
思路
①dp数组,1到i为节点组成的二叉搜索树的个数为dp[i]
②推导公式,dp[i] += dp[j - 1] * dp[i - j],j-1 是j为头节点左子树节点数量,i-j 是以j为头节点右子树节点数量
③dp数组初始化,因为涉及乘积,且每个i都可以通过i-1推导而来,所以dp[0]=1
④遍历顺序,双循环,遍历1到i的每个数,得到i之前的dp数组
⑤推导dp数组
代码
class Solution {
public:
int numTrees(int n) {
vector<int> dp(n + 1, 0);
dp[0] = 1;
// 遍历从1到n
for (int i = 1; i <= n; i++) {
// 遍历从1到i,得到dp数组中每个值
for (int j = 1; j <= i; j++) {
dp[i] += dp[j - 1] * dp[i - j];
}
}
return dp[n];
}
};
总结
①动态规划的突破点在于递推公式,就是要由前一个状态量推出当前状态量,想明白这个才能继续
②不要对题目进行完全模拟,只关注题目需要的东西。例如96.不同的搜索二叉树,并不需要构建树,只需要得到推导公式,按照动态规划五步曲即可