343. 整数拆分
思路:动态规划
1. dp数组及其下标的含义:拆分数字i,可以得到的最大乘积为dp[i];
2. 递推公式:dp[i] = Math.max( dp[i], Math.max(j*(i-j), j*dp[i-j]));
其中,j*(i-j) 代表拆分为 j 和 i-j,j*dp[i-j] 代表拆分为 j 以及和为 (i-j) 的若干个数;
此外,需要通过 j 遍历所有存在的值,取其中最大的作为当前 i 的 dp[i];
3. dp初始化:dp[0] 和 dp[1] 从定义上来说不应该初始化;dp[2] = 1;
4. 遍历顺序:从前往后遍历i,范围 [3,n];从前往后遍历j,范围[1,i/2];
其中,i 从3开始,dp[i-j] 就可以用得上初始化了的dp[2];
j 遍历到 i/2:拆分一个数,一定是拆成 m 个近似相同的子数时乘积最大;m一定大于等于2,也就是说,最差拆成两个相同的子树;因此 j <= i/2;
class Solution {
public int integerBreak(int n) {
int[] dp = new int[n+1];
dp[2] = 1;
for(int i=3;i<=n;i++){
for(int j=1;j<=i/2;j++){
dp[i] = Math.max(dp[i],Math.max(j*(i-j),j*dp[i-j]));
}
}
return dp[n];
}
}
思路:贪心算法
将正整数n进行有限次拆分为任意正整数,优先拆3,直到余数为4或2,此时子数乘积最大;
class Solution {
public int integerBreak(int n) {
if(n==2) return 1;
if(n==3) return 2;
if(n==4) return 4;
int result = 1;
while(n>4){
result*=3;
n-=3;
}
result*=n;
return result;
}
}
96.不同的二叉搜索树
思路:
1. 当n为1时候,有一棵二叉搜索树;当n为2时,有2棵二叉搜索树;
2. 当n为3时,共有5棵二叉搜索树:头节点为1时,右子树有2个节点,分布情况与n=2时的二叉搜索树的节点布局一致;头节点为2时,左右子树各有1个节点,分布情况与n=1时的二叉搜索树的节点布局一致;头节点为3时,左子树有2个节点,分布情况与n=2时的二叉搜索树的节点布局一致。递推关系:dp[3] = dp[2] * dp[0] + dp[1] * dp[1] + dp[0] * dp[2];
3. dp数组及其下标含义:dp[i] 代表以1~i为节点组成的二叉搜索树的数量;
4. 递推关系:dp[i] += dp[j-1] * dp[i-j];j-1 代表以 j 为头节点时左子树的节点数量,i-j 代表以 j 为头节点时右子树的节点数量;j代表头节点元素,范围[1,i];
5. 初始化:dp[0] = 1;(空节点也是一棵二叉搜索树)
6. 遍历顺序:从前往后遍历i,范围[1,n];从前往后遍历j,范围[1,i];
class Solution {
public int numTrees(int n) {
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];
}
}