一、BST特点
- 若任意节点的左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值;
- 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 任意节点的左、右子树也分别为二叉查找树。
二、题目
Given n, how many structurally unique BST’s (binary search trees) that store values 1…n?
For example,
Given n = 3, there are a total of 5 unique BST’s.
分析问题,可知,假设f(n)表示1~n个结点给出时,BST’s树的个数:
f(n) = f(0) * f(n-1) // 令1作为根,2~n右子树
+ f(1) * f(n-2) // 令2作为根,1作为左子树,3~n右子树
+ ……..
+ f(n-1)* f(0) //令n作根,1~n-1作为左子树。
递归形式符合卡塔兰数递归模型。
result[i]表示含有i个结点的二叉查找树的数量。然后依据上面分析的递推公式依次求出f(1), f(2),……f(n)
算法:
- 初始化容器前两项,后面才能开始迭代:
result.push_back(1);
result.push_back(1); - 计算含i个结点时二叉查找树的种类数,j表示1~i中取任一结点作为根。所以计算方式同递归一样,左子树(j-1)*右子树(i-j).
- 实现递推公式
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
//直接用卡特兰数地推公式
class Solution1 {
public:
int numTrees(int n) {
long long res = 1;
if (n==0)
return 1;
for (int i=1; i<=n; ++i)
res = res*2*(2*i-1)/(i+1);
return res > INT_MAX ? 0 : res;
}
};
//利用容器的方法
class Solution2
{
public:
int numTrees(int n){
vector<int> result;
result.push_back(1);
result.push_back(1);
for(int i=2;i<=n;i++){
int sum=0;
//计算含i个结点时二叉查找树的种类数,j表示1~i中取任一结点作为根。
for(int j=1;j<=i;j++){
sum+=(result[j-1]*result[i-j]); //根J的左树个数*右树个数
}
result.push_back(sum);
}
return result.back(); //result[n]
}
};
int main() {
Solution2 s;
cout << s.numTrees(3) << endl;
cout << s.numTrees(19) << endl;
return 0;
}
参考文献: