这道题的贪心思路是尽可能地拆分成3,(结论),需要进行数学证明,详细代码如下:
class Solution {
public:
int integerBreak(int n) {
if(n==2) return 1;
if(n==3) return 2;
if(n==4) return 4;
int res = 1;
while(n>4)
{
res*=3;
n-=3;
}
res*=n;
return res;
}
};
动态规划的思路为:
确定dp数组(dp table)以及下标的含义:dp[i]:分拆数字i,可以得到的最大乘积为dp[i]。
确定递推公式:
从1遍历j,然后有两种渠道得到dp[i],一个是j * (i - j) 直接相乘,一个是j * dp[i - j],相当于是拆分(i - j)。j怎么就不拆分呢?j是从1开始遍历,拆分j的情况,在遍历j的过程中其实都计算过了。那么从1遍历j,比较(i - j) * j和dp[i - j] * j 取最大的。所以递推公式:dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j))。其余步骤省略~详细代码如下:
class Solution {
public:
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;j++)
{
dp[i]=max(dp[i],max(j*(i-j),j*dp[i-j]));
}
}
return dp[n];
}
};
这道题的递推思路比较难想到,先看代码随想录进行学习:
来看n为3的时候情况。
当1为头结点的时候,其右子树有两个节点,这两个节点的布局,和 n 为2的时候两棵树的布局是一样的;
当3为头结点的时候,其左子树有两个节点,看这两个节点的布局,是不是和n为2的时候两棵树的布局也是一样的啊!
当2为头结点的时候,其左右子树都只有一个节点,布局和n为1的时候只有一棵树的布局也是一样的啊!
发现可以通过dp[1] 和 dp[2] 来推导出来dp[3]的某种方式。
dp[3],就是 元素1为头结点搜索树的数量 + 元素2为头结点搜索树的数量 + 元素3为头结点搜索树的数量
元素1为头结点搜索树的数量 = 右子树有2个元素的搜索树数量 * 左子树有0个元素的搜索树数量
元素2为头结点搜索树的数量 = 右子树有1个元素的搜索树数量 * 左子树有1个元素的搜索树数量
元素3为头结点搜索树的数量 = 右子树有0个元素的搜索树数量 * 左子树有2个元素的搜索树数量
有2个元素的搜索树数量就是dp[2]。
有1个元素的搜索树数量就是dp[1]。
有0个元素的搜索树数量就是dp[0]。
所以dp[3] = dp[2] * dp[0] + dp[1] * dp[1] + dp[0] * dp[2]
详细代码如下:
class Solution {
public:
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];
}
};