力扣-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);
    }
};

 

posted @ 2020-07-26 15:45  Peterxiazhen  阅读(150)  评论(0编辑  收藏  举报