五部曲,拆分整数,给定一个整数n,第一个数从1开始拆,会剩下n-1,于是从这里可看出,n-1又可以继续分为1和n-1.现有的状态依赖之前的状态,于是可以看出dp数组的定义了。计算完1之后,递增从2又开始拆。直到递增到n
- dp[i]代表的是将一个整数i拆分成k个整数的最大乘积值dp[i]。
- 递推公式:dp[i]=max(j*(i-j),j*dp[i-j],dp[i])。这里j代表的就是上面的从j开始拆,这里分了两种情况,一种是k为2的情况,两个数直接相乘即可,然后就是k大于2的情况。然后固定i值,以j为起点拆,j不同又会有很多种不同的结果,这里要取i等于某一个值时的最大dp[i]值
- 初始化:dp[0]=0,dp[1]=0,dp[2]=1,因为根据上面的递推公式,i=3时才能拆分多种情况,才能使用递推公式。
- 从小到大遍历
class Solution {
public int integerBreak(int n) {
int[] dp=new int[n+1];
dp[0]=0;
dp[1]=0;
dp[2]=1;
for(int i=3;i<n+1;i++){
for(int j=1;j<=i/2;j++){//对i进行拆分,求dp[i]
//这里要取dp[i]的最大值
dp[i]=Math.max(Math.max((j*(i-j)),j*dp[i-j]),dp[i]);
}
}
return dp[n];
}
}
这一题可以看出,选择不同的头结点,其左右子数就是之前经历过的状态。这里没有想到是dp[左子树]*dp[右子树]。只发现了当前状态可以拆分成之前的状态
- dp[i]代表的是由i个节点组成的互不相同的二叉搜索树的数量值为dp[i]
- 递推公式:先选择一个头结点为j,j从1开始遍历直到i;dp[i]+=dp[j-1]dp[i-j]
- 初始化:dp[0]=0,因为dp[1]可以由递推公式推出了
- 遍历顺序,i从小到大遍历
class Solution {
public int numTrees(int n) {
int[] dp=new int[n+1];
dp[0]=1;
for(int i=1;i<n+1;i++){
for(int j=1;j<=i;j++){
dp[i]+=dp[j-1]*dp[i-j];
}
}
return dp[n];
}
}