有多少个不同的二叉搜索树
此题首先得明白什么是二叉搜索树(BST),二叉搜索树即这样的一种结构,每个结点存放一个值,这个结点为根的左子树上存放的值小于这个值,右子树存放的大于这个值,并且左右子树都是BST。
此题给出的条件确定了每个结点的值都是不相同的。
正因如此,1,2,3,4序列可组成的BST的个数和6,7,8,9可组成的BST的个数是一样的。
这能给我们什么启示呢?从本质上来说,6,7,8,9可以看做是1,2,3,4全体加5的结果。
全体加5并不会影响BST树是BST树。因此,上述两个序列可组成BST的个数是一样的。
那么对于一个1…n序列有多少种可能性呢?
由于值是互不相同的,因此所组成的BST的根结点的值只有n个。
因此,如果我们能计算出 根节点值相同的情况下可组成的BST的个数,再把这n种情况得到的结果相加,就能得到1…n序列可组成BST的总数。
又由于序列[1,…,n]和序列[m+1,…m+n]可组成的BST的总数是一样的。
所以如果我们去掉[1…n]序列中的根值m,根据BST的性质得到两个序列[1…m-1]和[m+1,…,n]。
定义dp[i] 为结点个数为i,总共可以组成BST的个数。
所以对于根植为m的可组成BST的总数为 dp[m-1]*dp[n-m]。
按相同的方式计算1-n中所有的结点,即可得到dp[n]。
#include <bits/stdc++.h>
using namespace std;
int main () {
int n;
scanf("%d", &n);
vector<int> dp(n+1);//dp(i) 结点个数为i 总共可以组成 BST 的个数
dp[0] = dp[1] = 1;//dp[0] 取1是为了之后相乘时不出现乘0结果为0的情况
int left, right, sum;
for(int i = 2; i <= n; ++i) {
sum = 0;//计算结果初始化
for(int j = 0; j < i; ++j) {//左边结点从0枚举到n-1 根的值从1到n
left = j;//计算当前结点左边有的结点个数
right = i - j - 1;//右边的结点个数
sum += dp[left] * dp[right];//两个情况相乘
}
dp[i] = sum;//当前所有的可能性
}
printf("%d", dp[n]);
return 0;
}