dp题的关键在于寻找状态转移方程。
目录
一、题目
给你一个整数
n
,求恰由n
个节点组成且节点值从1
到n
互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。(来源:leetcode)
示例 1:
输入:n = 3 输出:5示例 2:
输入:n = 1 输出:1
二、确定dp数组含义及其下标含义
由题目可得,dp[i]的含义是:第i个节点组成且节点值从 1
到 i互不相同的 二叉搜索树 有dp[i]种。
三、推导递推公式
从dp[3]可以看出:
dp[3]的所有情况可以分为:
左子树的根节点是2的所有情况 * 右子树的根节点是0的所有情况+
左子树是的根节点1的所有情况 * 右子树的根节点是1的所有情况+
左子树是的根节点0的所有情况 * 右子树是的根节点2的所有情况
左子树的根节点是1的所有情况 * 右子树的根节点是0的所有情况+
左子树的根节点是0的所有情况 * 右子树的根节点是1的所有情况
dp[1]:
只够组成一个根节点,无法区分左右子树
所以可以推导出:dp[i] += dp[以(j-1)为根节点的情况] * dp[以(i-j)为根节点的情况](j 从1遍历到i)
四、确定如何初始化
由以上的分析可以知道,dp[1]由dp[0]得到,dp[2]由dp[1]+dp[0] + dp[0]+dp[1]得到,每个i由之前的i-1一直到0的所有dp[i]组成,所以只需要初始化一个dp[0] = 1。(认为空树有一个空结点)
五、确定遍历顺序
由四可知,我们需要从前往后遍历才能得到经过计算的值。
六、举例推导dp数组
七、代码实现
class Solution {
public:
int numTrees(int n) {
vector<int> dp(n+1);
dp[0] = 1;
// 求以n为头节点的树个数
for(int i = 1; i <= n; i++)
{
// 求以i为头节点的树个数
for(int j = 1; j <= i; j++)
{
dp[i] += dp[j-1] * dp[i-j];
}
}
return dp[n];
}
};
总结
这道题的难点在于递推公式的推导比较抽象,这就要求我们时刻记住第一步自己确定好的各种含义,在推导递推公式过程中,把握下一个状态是怎么能从上一个状态变化得到这一原则,勤加练习!