343.整数拆分
解题思路:
这个题主要还是在于这个递推公式,为什么是dp[i] = max(dp[i], dp[i - j] * j, (i - j) * j)
而不是dp[i] = max(dp[i], dp[i - j] * dp[j], (i - j) * j)
原因是因为j是从1一直向上增的,拆分j的情况,我们在之前的遍历过程中已经计算过了。所以这里拆完的j并不需要继续拆分。他已经成为了拆分之后乘积中的一个数字成员。
class Solution {
public int integerBreak(int n) {
/**
* 1.dp[i] 数字i拆分之后可以获得的最大乘积
* 2.dp[i] = max(dp[i], dp[i - j] * j, (i - j) * j)
* 3.dp[2] = 1
* 4.肯定是正向循环
*/
int[] dp = new int[n + 1];
dp[2] = 1;
for(int i = 3; i <= n; i++){
dp[i] = i - 1;
for(int j = 2; j <= i - j; j++){
dp[i] = Math.max(dp[i], Math.max(dp[i - j] * j, (i - j) * j));
}
}
return dp[n];
}
}
96.不同的二叉搜索树
题目链接:96. 不同的二叉搜索树 - 力扣(LeetCode)
解题思路:
这个题也是第一时间没想到递推关系式:
应该想到以不同结点为根节点来区分不同情况的。
还有一个关机点在于:dp[1]其实也可以包含在循环内,没有必要将他拿出来单独处理。
class Solution {
public int numTrees(int n) {
/**
* 1.dp[i] i个结点的二叉搜索树种类
* 2.dp[i] += dp[j - 1] * dp[i - j]
* 3.dp[1] = 1 dp[2] = 2
* 4.正向遍历
*/
if(n == 1 || n == 2) return n;
int[] dp = new int[n + 1];
dp[0] = 1;
dp[1] = 1;
for(int i = 2; i <= n; i++){
for(int j = 1; j <= i; j++){
dp[i] += dp[j - 1] * dp[i - j];
}
}
return dp[n];
}
}
改进代码:
class Solution {
public int numTrees(int n) {
/**
* 1.dp[i] i个结点的二叉搜索树种类
* 2.dp[i] += dp[j - 1] * dp[i - j]
* 3.dp[1] = 1 dp[2] = 2
* 4.正向遍历
*/
int[] dp = new int[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];
}
}