343. 整数拆分
思路
一个动态规划问题最重要的就是找到递推公式,找到递推公式,整个题就已经解出来了。
这道题看到时会想分成几份比较好,等于10时与之前的数有什么关系。。。
- 确定数组及含义
dp[i]表示正整数等于i时所获得的最大乘积。 - 确定递推公式
dp[i-j]表示将i-j分成了至少2份,dp[i] = j * dp[i-j]表示至少将dp分成3份。这样少了将dp[i]分成2分的情况,需要再补上j*[i-j]。 - 初始化
至少从2开始,初始化dp[2] = 1;
4.遍历顺序,从前向后遍历
实现
点击查看代码
class Solution {
public:
int integerBreak(int n) {
vector<int> dp(n+1);
dp[2] = 1;
for(int i = 3; i <= n; i++) {
for(int j = 1; j < i; j++) {
dp[i] = max(dp[i],max(j*(i-j),j*dp[i-j]));
}
}
return dp[n];
}
};
复杂度分析
- 时间复杂度:O(n*n)
- 空间复杂度:O(n)
96. 不同的二叉搜索树
思路
寻找规律:
- n = 1,结果为1,dp[1] = 1;
- n = 2,头节点为1,有1种结果,头节点为2,有一种结果。dp[2] = 2;
- n = 3
- 头节点为1,左子树有0个节点,右子树有两个节点,与n=2情况一致
- 头节点为2,左子树有一个节点,与n=1情况一致,右子树有一个节点,与n=1情况一致
- 头节点为3,左子树有两个个点,与n=2情况一致,右子树有0个节点
所以dp[3] = dp[0] * dp[2] + dp[1] * dp[1] + dp[2] * dp[0];
我们不妨设n=0时,结果为1。即dp[0] = 1,则dp[3] = 5
实现
点击查看代码
class Solution {
public:
int numTrees(int n) {
if(n <= 1) return 1;
vector<int> dp(n+1);
dp[0] = 1;
dp[1] = 1;
dp[2] = 2;
for(int i = 3; i <= n; i++) {
for(int j = 1;j <= i; j++) {
dp[i] += dp[j-1] * dp[i-j];
}
}
return dp[n];
}
};
复杂度分析
- 时间复杂度:O(n*n)
- 空间复杂度:O(n)