前言
我在刷卡哥的“代码随想录”,自己的总结笔记均会放在“算法刷题-代码随想录”该专栏下。
代码随想录此题链接
思路
通过“动态规划五步曲”,
- 确定dp数组含义:dp[i] = n,是当节点数为i时,总共的二叉搜索树的种类为n种。
- 确定递推公式:dp[i] += dp[j - 1] * dp[i - j] (j从1~i,其中j-1代表当前节点的左子树的二叉搜索树的种类;i-j代表当前节点右子树二叉搜索树的种类)
- 初始化:
- 遍历方向:节点数从小到大,先算出数量少的结点的二叉搜索树的数量,才能根据递推公式推算出数量更大的头结点的二叉搜索树的数量。
- 举例,当n=3,dp数组为[1,2,5]。具体二叉搜索树情况如下:
3. 算法实现
public int numTrees(int n) {
//1.确定递推数组以及下标含义dp[i] = n i是一共有多少个节点 n是一共有多少种不同的二叉搜索树
//2.确定递推公式 dp[i] = dp[j - 1] + dp[i - j] (j∈[1,i])
//3.初始化 dp[0] = 1 (0个节点,一共一种,空二叉搜索树)
//4.确定递推顺序 从前向后,求每个节点数为i时,当前头结点设为j,都以1开始到i结束
//5.举例 n=3,dp数组[1,2,5]
//最后要求出的是 dp[n],但是得一步步求出之前的dp数组的数值
int[] dp = new int[n + 1];//n个节点,从0节点开始,下标有n+1个
dp[0] = 1;
for(int i = 1;i <= n;i++){//从前往后求出每个i的值
for(int j = 1;j <= i;j++){//求出当前i的值,是从1开始到i为节点所有树的累加
dp[i] += dp[j - 1] * dp[i - j];//dp[j - 1]是左子树的二叉搜索树的种类,dp[i - j]是右子树的二叉搜索树的种类
}
}
return dp[n];
}
4. 算法坑点
- 不好想到递推公式