力扣-96-不同的二叉搜索树
题目:传送门
题目分析:二叉搜索树:若左子树不空,则左子树上的所有结点的值均小于它的根节点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根节点的值。那么,我们给定一个有序的序列$1\cdots n$。为了构造出一棵二叉搜索树,我们可以遍历每个数字$i$,将其作为根节点,并将$1\cdots \left ( i-1 \right )$作为左子树,将$\left ( i+1 \right )\cdots n$作为右子树。接着我们可以按照同样的方式递归构建左子树和右子树。
方法一:动态规划
$G\left ( n \right )$:长为$n$的序列能构成的不同的二叉搜索树的数目。
$F\left (i, n \right )$:以$i$为根节点,长度为$n$的序列能构成的不同二叉搜索树的个数。
很容易得到:$G\left ( n \right )=\sum_{i=1}^{n}F\left (i, n \right )\left ( 1 \right )$ 特殊的$G\left ( 0 \right )=G\left ( 1 \right )=1$
又因为:$F\left ( i,n \right )=G\left ( i-1 \right )G\left ( n-i \right )\left ( 2 \right )$
联立①②两式得:
$G\left ( n \right )=\sum_{i=1}^{n}G\left ( i-1 \right )G\left ( n-i \right )\left ( 3 \right )$
/*推导公式:G(n) = sigma_{i=1}^{i<=n} G(i-1)·G(n-i)*/ #include <vector> class Solution { public: int numTrees(int n) { vector<int> res(n + 1); res[0] = 1; res[1] = 1; for(int i = 2; i <= n; i++) for(int j = 1; j <= i; j++){ res[i] += res[j - 1] * res[i - j]; } return res[n]; } };
方法二、卡特兰数
式子三的形式属于卡特兰数,故可以根据卡特兰数的通项公式求解:
$C_{n+1}=\frac{2\left ( 2n+1 \right )}{n+2}C_{n}$
/*推导公式:G(n) = sigma_{i=1}^{i<=n} G(i-1)·G(n-i)*/ #include <vector> typedef long long ll; class Solution { public: int numTrees(int n) { ll ans = 1; for(int i = 0; i < n; i++){ ans = ans * 2 * (2*i+1) / (i+2); } return int(ans); } };
作者:Ryanjie
出处:http://www.cnblogs.com/ryanjan/
本文版权归作者和博客园所有,欢迎转载。转载请在留言板处留言给我,且在文章标明原文链接,谢谢!
如果您觉得本篇博文对您有所收获,觉得我还算用心,请点击右下角的 [推荐],谢谢!