目录
343. 整数拆分
题解思路:
题目还是动态规划的常规题目,使用n+1数组保存0-n范围内正整数拆分后的最大值,这里最大值的取法需要注意,要考虑三种情况:
1、拆成两个数的情况:12 , 21
2、拆成三个数(dp[i]至少会拆分成两个数)及以上的情况:dp[3]就是看dp[2]*1、dp[1]*2 ,dp[4]就是看dp[3]*1、dp[2]*2、dp[1]*3
3、还有就是要保持dp[3]要最大,只有拆分比当前dp[3]大的时候,此时才更新dp[3]
class Solution {
public int integerBreak(int n) {
//动规第一步:确定dp[i]的含义:整数i拆分后得到的乘积最大值
//动规第二步:确定递推公式:这里其实还是依赖上一个数拆分后取得的最大值,比如dp[3]最大值就是看
//拆成两个数的情况:1*2 , 2*1
//拆成三个数(dp[i]至少会拆分成两个数)及以上的情况:dp[3]就是看dp[2]*1、dp[1]*2 ,dp[4]就是看dp[3]*1、dp[2]*2、dp[1]*3
//还有就是要保持dp[3]要最大,只有拆分比当前dp[3]大的时候,此时才更新dp[3]
//综合上述三点其递推公式为:dp[i] = Math.max{ (i - j)*j, dp[i-j]*j, dp[i]}
//动规第三步:初始化dp数组:dp[1] = 0 dp[2] = 1
//动规第四步:确定遍历顺序:从前往后遍历
//动规第五步:打印dp数组
int[] dp = new int[n+1];
dp[0] = 0;
dp[1] = 0;
dp[2] = 1;
for(int i = 3; i < dp.length; i++){
for(int j = 1; j < i; j++){
dp[i] = Math.max(Math.max((i - j)*j, dp[i-j]*j), dp[i]); //Math.max(a,b)只能两者比较取其一
}
}
return dp[dp.length-1];
}
}
题解思路:
依然是动态规划的常规题,跟着卡哥按部就班刷下来确实有点感觉了,想知道输入n后,即有n个节点一共有多少种不同二叉搜素树的个数,还是得依赖于有n-1个节点时构成的二叉搜索树的个数,但是需要考虑左右子树在不同的节点个数情况下的排列组合,具体说明见代码注释!!!
class Solution {
public int numTrees(int n) {
//确定dp[i]的含义:输入i,也就是i个节点组成二叉搜索树的种树
int[] dp = new int[n+1];
dp[0] = 1;
dp[1] = 1;
if(n > 1) dp[2] = 2;
for(int i = 3; i < n + 1; i++){ //控制dp数组的下标dp[i]
for(int j = 1; j <= i; j++){ //控制头节点的值,根据二叉搜索树的特性,左子树的值 < 根节点的值 < 右子树的值,则根节点的值-1 = 左子树的节点个数, i-根节点的值 = 右子树的节点个数
dp[i] += dp[j - 1] * dp[i - j]; //dp[i-1]:就是左子树有i-1个节点时,总共有dp[i-1]种不同的二叉树
//dp[i -j]:就是右子树有j-i个节点时,总共有dp[i-j]种不同的二叉树
//对左右二叉树的个数排列组合就是相乘得到总的
}
}
return dp[n];
}
}