96. 不同的二叉搜索树

给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?

示例:

输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树:

   1         3     3      2      1
           /     /      /       
     3     2     1      1   3      2
    /     /                        
   2     1         2                 3

方法一:动态规划 

代码:

 1 class Solution {
 2 public:
 3     int numTrees(int n) {
 4         if(n == 0 || n == 1) return n;
 5         vector<int> a(n + 1,0);
 6         a[0] = 1, a[1] = 1;
 7         for(int i = 2;i <= n;++i){
 8             for(int j = 1;j <= i;++j) {
 9                 a[i] += a[i-j]*a[j-1];
10             }
11         }
12         return a[n];
13     }
14 };

思路:可怜的我完全没有思路。最后这里还是要感谢官方题解。这里我用自己的语言来复述一些官方动归的思路。

为了便于推导出递推公式,需要借助两个函数:

G(n):长度为n的整数能生成的二叉树的种类

F(i,n):以i为根的二叉树的种类,其中(1≤i≤n)

那么应当有[G(n) = sumlimits_{i = 1}^n {F(i,n)} ]

。因为以i为根则生成的二叉树不同,所以最后G(n)可以看成是以i(1≤i≤n)为根的所有类型二叉树种类的和。

对于F(i,n),其所能生产的二叉树种类可以看成子问题(1,i-1)(i+1,n)两部分组成的种类的积。

所以[F(i,n) = G(i - 1)G(n - i)],因此可以求出递推方程[G(n) = sumlimits_{i = 1}^n {G(i - 1)G(n - i)}]。

分析:最后时间复杂度为O(n2),空间复杂度O(n)。


方法二:数学演绎法

其实这里的G(n)就是所谓的卡特兰数,因此可以用通项公式直接求出来,这里采用了递推公式

[{C_0} = 1,{C_{n + 1}} = frac{{2(2n + 1)}}{{n + 2}}{C_n}]

可以直接推导出结果。

代码:

 1 class Solution {
 2 public:
 3     int numTrees(int n) {
 4         int c = 1;
 5         for(int i = 1;i<n;++i){
 6             c *=2*(2*n+1)/(n+2);
 7         }
 8         return c;
 9     }
10 };

结论:时间复杂度为O(n),空间复杂度O(1)。

写在最后:卡特兰数虽然有通项公式

[{C_n} = frac{1}{{n + 1}}C_{2n}^n]

但是求解起来并不简单啊,还不如乖乖地推。

 

原文地址:https://www.cnblogs.com/Swetchine/p/12708387.html