参考资料:代码随想录
题目链接:. - 力扣(LeetCode)
本题开始真的难到我了,看题解也很难理解,主要是涉及到了二叉树就很绕。跟随题解一步步思考,思路也就逐渐清晰,对动态规划也有了更清晰的认识。
1.确定dp数组含义
本道题的dp数组含义为,第i个下标代表由几个节点组成的二叉树,有几种方法。
以n=3为例,dp[0]代表0个节点的情况下,能组成几种二叉树。
d[1]代表1个节点下的情况,能组成几种二叉树。
dp[2]代表2个节点的情况下,能组成几种二叉树。
dp[3]代表3个节点的情况下,能组成几种二叉树。
2.初始化dp数组
本题的dp[0]初始化为1,可以理解为只有1才能推出正确结果,我不认同0个节点它也是二叉树,初始化为1完全就是能推出正确结果。
3.确定递推公式
以n=3为例,这几种二叉树大体上是由头节点1、2、3组成的,n=3的情况下,有几种二叉树等于头结点1的二叉树数量+头结点2的二叉树数量+头结点3的二叉树数量。
所以由此衍生出了一个变量"j",这个“j”就是控制头结点数值的。n为几那么j也就到几。所以递推公式初具雏形就是dp[i]+=xxx,这个+=的次数就是由头结点数量控制的。
那么具体的递推公式是什么,假设n=3,头结点j=1的话,头结点为1的二叉树数量=左子树数量*右子树数量,以此类推加3次,就得出了n个节点有几种二叉树了
4.确定遍历顺序
上述提到了,后面的的状态是依赖前面的状态推导出来的,所以是从前向后遍历。
class Solution {
public int numTrees(int n) {
//1.确定dp数组含义
int[] dp = new int[n+1];
//2.初始化dp数组
dp[0] = 1;
//3.确定遍历顺序
for(int i = 1;i <= n;i++){
for(int j = 1;j <= i;j++){
//4.确定递推公式
dp[i] += dp[j-1] * dp[i-j];
}
}
return dp[n];
}
}
清晰的看出有n个节点时,有几种二叉树,且头结点为j时怎么组成的
public static void main(String[] args) {
int n = 4;
//1.确定dp数组含义
int[] dp = new int[n+1];
//2.初始化dp数组
dp[0] = 1;
//3.确定遍历顺序
for(int i = 1;i <= n;i++){
System.out.println("当n="+i+"时,一共有"+i+"个节点");
for(int j = 1;j <= i;j++){
//4.确定递推公式
dp[i] += dp[j-1] * dp[i-j];
int i1 = dp[j - 1] * dp[i - j];
System.out.println("头结点为"+j+"时,有左子树数量"+dp[j-1]+"*右子树数量"+dp[i-j]+"="+ i1 +"种二叉树");
}
}
System.out.println(Arrays.toString(dp));
//return dp[n];
}