力扣-动态规划-96. 不同的二叉搜索树
96. 不同的二叉搜索树
题目描述
给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
示例 1:
输入:n = 3
输出:5
示例 2:
输入:n = 1
输出:1
提示:
1 <= n <= 19
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-paths-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:动态规划
今天接着刷第六道动态规划的题目,动态规划的题目越刷越有意思,有点像是找规律。
我相信像我这样刷题不多的新手刚刚看到题目时几乎不可能一下子找到递推公式,肯定会经过痛苦且快乐的找规律的过程。我寻找递推公式没有什么诀窍,就是一个笨办法,在纸上举例模拟n增加的过程,然后不断寻找不同n之间的关系。随着模拟n增加的过程,就发现,当以i到n分别作为头结点时,可以把所有的情况模拟完。发现这个之后接着推导以i作为头结点的不同二叉搜索树的数量,在纸上把二叉树简单画出来之后发现,i左边的节点数量为i-1,i节点右边的节点数量为总结点数量n-i。而i节点的左边子树组合*i节点右边子树的组合就是i作为头结点能够形成的二叉搜索树的数量,用递推公式来表示就是:dp[i] = dp[i - 1] + dp[n - i],其中i是头结点的值,n代表总的节点个数。而所有的二叉搜索树个数=dp[1] + dp[2] + dp[3] + …+ dp[n],分别用1到n作为头结点的二叉搜索树。
有了上面的发现,我们就可以按照动态规划的步骤完成这道题了。
//1.确定dp数组的含义 dp[i]代表由i个节点组成的二叉搜索树有dp[i]种。
//2.递推公式:dp[i]=以节点1到i依次作为头结点的二叉搜索树的组合相加,
// 以i为头结点二叉搜索树的组合 = 左边组合数 * 右边组合数 = dp[i - 1]*dp[n - i]。
//3.初始化 要保证乘积有效 dp[0]和dp[1]初始化为1
//4.遍历顺序 从1开始到n依次作为头结点遍历
//5.举例推导
我自己写的代码如下,代码已经加了注释,各位小伙伴如果有什么问题可以在评论里提出来,欢迎大家交流。
//动态规划 前面的状态会影响到后面的决策
public int numTrees(int n) {
//1.确定dp数组的含义 dp[i]代表由i给节点组成的二叉树有的dp[i]种
//2.递推公式:dp[i]=以节点1到i依次作为头结点的二叉搜索树的组合相加
// 以i为头结点二叉搜索树的组合 = 左边组合数 * 右边组合数 = dp[i - 1]*dp[n - i]
//3.初始化 要保证乘积有效 dp[0]和dp[1]初始化为1
//4.遍历顺序 从1开始到n依次作为头结点遍历
//5.举例推导
int[] dp = new int[n+1];
dp[0] = 1;
dp[1] = 1;
for (int index = 2; index <= n; index++) {//遍历dp的下标 index代表由index个节点
for (int i = 1; i <= index; i++) {//遍历头结点 需要注意头结点是从1到index
dp[index] += dp[i - 1] * dp[index - i];//头结点i的左子节点数量是i-1,右子节点数量是:总的节点数量-i
}
}
return dp[n];
}
另外附上我自己搭建的个人博客网址,里面记录了我之前记录的学习心得,欢迎大家交流讨论。