343. 整数拆分
给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。
示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。
示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
说明: 你可以假设 n 不小于 2 且不大于 58。
解题思路
定义动态规划数组dp[i]
表示对于正整数i拆分后的最大乘积
确定递推公式
对于正整数i,怎样拆分能得到最大的乘积呢?
通过一些数学上的证明发现,当拆分后的各个数字大小接近时,乘积较大。
所以按照这个思路需要将i尽可能的拆分为大小接近的2个及以上的数子,然后再依次比较找到最大乘积。
假如dp[i] 拆分为两个数字,则可以表示为
j*(i-j)
如果拆分为三个及以上的数字,则可以表示为
j*dp[i-j]
由此可以得出递推公式为:
dp[i] = max({dp[i], (i - j) * j, dp[i - j] * j})
dp数组初始化
因为dp[0]和dp[1] 没有意义,所以i 从3开始,j从1开始,只需要初始化dp[2]。
dp[2] = 1
代码实现-java
class Solution {
public int integerBreak(int n) {
// 定义dp数组
int[] dp = new int[n+1];
// 初始化
dp[2] = 1;
// 遍历
for(int i=3;i<=n;i++){
// j 最大值为 i-j,再大只不过是重复而已
for(int j=1;j<=i-j;j++){
dp[i] = Math.max(dp[i],Math.max(j*dp[i-j],j*(i-j)));
}
}
return dp[n];
}
}
96.不同的二叉搜索树
给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?
解题思路
什么是二叉搜索树?
二叉搜索树是一个有序树:
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉搜索树
当n =1时,只有一颗搜索树
当n=2时,有两颗搜索树
当n=3时,
如果1为头结点,那么2和3只能都在右子树上,对于右子树的布将于n=2的布局相同
如果2为头结点,那么1只能在左子树,3只能在右子树,左右子树各有一个节点,与n=1的布局相似
如果3为头结点,那么1,2只能在左子树,此时左子树布局相当于n=2的布局
从以上分析就能发现一些规律,n=3的布局其实可以由n=1和n=2推导出来
定义dp[i]数组:表示n=i时,以1...i组成的二叉搜索树的数量
其推导公式为:dp[3] = dp[2] * dp[0] + dp[1] * dp[1] + dp[0] * dp[2]
所以可以得到递推公式:dp[i] += dp[j - 1] * dp[i - j] (j-1 为j为头结点左子树节点数量,i-j 为以j为头结点右子树节点数量)
dp数组初始化
dp[0] = 1(可以认为空节点也是一颗二叉搜索树)
确定遍历顺序
从小到大遍历节点数
代码实现-java
class Solution {
public int numTrees(int n) {
// 定义dp数组
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];
}
}