赞
踩
class Solution {
public:
int numTrees(int n){
}
分析
给定一个数n,怎么去构建一颗二叉搜索树呢?
[1,5]
,我们应该怎么构建树呢?
[1, 4]
都必须是它的左子树[1, 3]
必须是它的左子树,[5]
必须是它的右子树[1, 2]
必须是它的左子树,[4, 5]
必须是它的右子树[1]
必须是它的左子树,[3, 5]
必须是它的右子树[2, 5]
必须是它的右子树[1, 3]
都必须是它的左子树[1, 2]
必须是它的左子树,[4,5]
必须是它的右子树对于上面分析,我们用书面语言来总结一下:
i
,然后将该数字作为树根,将1...(i-1)
序列作为左子树,将(i + 1) ... n
序列作为右子树。接着我们可以按照同样的方式递归构建左子树和右子树。从上面可以看出,对于一个数5,它的最优子结构是:
那么,设以i为根节点的二叉搜索树为f(i),那么其最优子结构和原问题有什么关系呢?假设给定长度为5的序列,那么
5
的序列能构成的不同二叉搜索树的个数 = 以5为根节点,构建的二叉搜索树数量 + 以4为根节点,构建的二叉搜索树数量 + 以3为根节点,构建的二叉搜索树数量 + 以2为根节点,构建的二叉搜索树数量 + 以1为根节点,构建的二叉搜索树数量 =f(1) + f(2) + f(3) + f(4) + f(5)思路
(1)定义状态
由于题目是要求我们计算不同二叉搜索树的个数,因此我们可以定义两个函数:
G(n)
:长度为n
的序列能构成的不同二叉搜索树的个数f(i)
:以i
为根的二叉搜索树的个数。则有
G
(
n
)
=
f
(
1
)
+
f
(
2
)
+
f
(
3
)
+
.
.
.
f
(
n
)
G(n)=f(1)+f(2)+f(3)+...f(n)
G(n)=f(1)+f(2)+f(3)+...f(n)
(2)推导公式。关键要推导出f(i)。
[1,2,3...i-1]
,右子树节点个数为[i+1, i+2,... n]
i-1
个,右子树节点为n-i
个,即f(i) = G(i-1)*G(n-i)
(3)对于边界情况
1 n = 1
2 1 n = 2
/ \
1 2
1 3 3 2 1 n = 3
\ / / / \ \
3 2 1 1 3 2
/ / \ \
2 1 2 3
总结
class Solution { public: int numTrees(int n) { std::vector<int> dp(n + 1); dp[0] = dp[1] = 1; for (int i = 2; i <= n; ++i) { for (int j = 1; j <= i; ++j) { dp[i] += dp[j - 1] * dp[i - j]; } // dp[2] = dp[0] * dp[1] + dp[1] * dp[0]; } return dp[n]; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。