343. 整数拆分
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-1; j++) {
dp[i] = max(dp[i], max(j * (i-j), j * dp[i-j]));
}
}
return dp[n];
}
这道题的关键就是将dp[i]转换为 max(j * (i-j), j * dp[i-j]),也就是在分成两个数还有两个以上的数中的最大值,由于遍历的时候dp[i-j]已经是最大值了,所以只需要比较这两个值即可。
可以进一步进行优化:因为拆分一个数n 使之乘积最大,那么一定是拆分成m个近似相同的子数相乘才是最大的。那么 j 遍历,只需要遍历到 n/2 就可以,后面就没有必要遍历了,一定不是最大值。
for (int i = 3; i <= n ; i++) {
for (int j = 1; j <= i / 2; j++) {
dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
}
}
96.不同的二叉搜索树
int numTrees(int n) {
vector<int> dp(n+1);
dp[0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
dp[i] += dp[j-1]*dp[i-j];
}
}
return dp[n];
}
这道题自己想是真想不出来,思路是n等于i时,他不同的二叉搜索树的数量等于以1为根节点的数量加以2为根节点的数量一直加到以i为根节点的数量。而以i为根节点的数量要由它不同的左右子树的数量相乘来得到。由于是二叉搜索数,所以左子树都是小于根节点的,数量为i-1,右子树都是大于根节点的,数量为n-i这样就能得到递推公式了:
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
dp[i] += dp[j-1]*dp[i-j];
}
}