代码随想录训练营Day41 | Leetcode 343、96
一、343 整数拆分
题目链接:343 整数拆分
核心:整数拆分后的乘积最大值要么是拆分后数字相乘值最大,要么是拆分前值最大(也存在这种可能),而拆分后数字相乘又存在2种情况,其一是拆分成2个数字的相乘:j*(i-j);其二是拆分成3个或3个以上数字的相乘,而这多个数字相乘总可以看成1个数字与其余几个数字相乘后结果的相乘:jdp[i-j]。
第一,dp数组的定义:dp[i]表示整数i拆分后的最大乘积,即下标值对应整数;
第二,递推公式:dp[i]=max(dp[i],max(j(i-j),j*dp[i-j]));
第三,初始化:dp[2]=1,n的范围是从2到58;
第四,遍历顺序,从小到大,外循环i从3到n;内循环是拆分的数字j从1到i-1(优化处理可令j从1到i/2,因为超过i/2的整数与前面重复)。
int integerBreak(int n) {
//动态规划,
vector<int> dp(n+1); //下标对应n,记录从2到n的最大乘积
dp[2]=1; //n=2的最大乘积是1
for(int i=3;i<=n;++i)
{//i是从3开始拆分,直到n;j是拆分后的另一部分(可能是1个整数也可能是多个整数)
//for(int j=1;j<i-1;++j)
for(int j=1;j<=i/2;++j) //优化j的结束位置,只要拆分到一半(乘积最大必然存在相同数
dp[i]=max(dp[i],max(j*(i-j),j*dp[i-j]));
}
return dp[n];
}
二、96 不同的二叉搜索树
题目链接:96 不同的二叉搜索树
核心:整数n的二叉搜索树数量为头节点从1到n的二叉搜索树数量之和,而头节点为j的二叉搜索树数量是左子树有j-1(比j小)个元素的搜索树数量*右子树有n-j(比j大)个元素的搜索树数量。
思想与整数拆分有点类似,i从整数1遍历到n,j表示头节点元素值,从1遍历到i。
int numTrees(int n) {
//动态规划,整数n的二叉搜索树:头节点从1开始到n,1的左右子树相乘,2的左右子数相乘
vector<int> dp(n+1); //记录整数n的二叉搜索树,下标i对应整数i
dp[0]=1; //初始化,整数0也被视为1棵二叉树(空节点)
for(int i=1;i<=n;++i)
{//i:从1遍历到n,j:整数i的二叉树情况:从1到i
for(int j=1;j<=i;++j)
dp[i]+=dp[j-1]*dp[i-j]; //dp[j-1]为左子树的二叉树,dp[i-j]为右子树的二叉树
}
return dp[n];
}