题目:Given n, how many structurally unique BST's (binary search trees) that store values 1 ... n?
Example:
Input: 3 Output: 5 Explanation: Given n = 3, there are a total of 5 unique BST's: 1 3 3 2 1 \ / / / \ \ 3 2 1 1 3 2 / / \ \ 2 1 2 3
通过学习95题(https://blog.csdn.net/ytwang95/article/details/81624920)之后,我们已经对二叉搜索树有了一定的了解。这道题只需要计算结果树的个数。因此既可以考虑迭代的方式,也可以用动态规划。
思路一:迭代:
对于一个节点i,当其为根节点时,左子树的节点范围为[1,...i-1],右子树的节点范围为[i+1,...n]。对这个根节点来说,二叉树的个数为左子树的个数乘以右子树的个数。则从[1,n]选择根节点,递归计算其左右子树的个数,再将它们相乘,累加就是结果树的个数。
然而……事实证明……会超时……
代码如下:
class Solution {
public:
int numTrees(int n) {
if(n<=1) return 1;
int count=0;
for(int i=1;i<=n;++i)
count+=numTrees(i-1)*numTrees(n-i);
return count;
}
};
思路二:动态规划
当n=1时
1 (1种)
当n=2时
1 2 (2种=[null,2]+[1,null])
\ /
2 1
抽象为:
root
/ \
left right
n=3时
left (节点个数) | right(节点个数) |
0 | 2 |
1 | 1 |
2 | 0 |
可以将问题看作是去一个节点做根节点,其余分为左右子树,考虑左右子树的可能个数,利用动态规划,用一个数组count[i]存储节点个数为i的树的可能个数,每次算新的结果会用到前面的结果。
n=3为例:
结果树的个数为:count[0]*count[2]+count[1]*count[1]+count[2]*count[0]
看了大神们的博客发现这个叫做卡特兰数 。即:
代码如下:
class Solution {
public:
int numTrees(int n) {
if(n==0) return 0;
int *count=new int[n+1];
count[0]=1;
count[1]=1;
if(n==1) return 1;
for(int i=2;i<=n;i++){
count[i]=0;
for(int j=1;j<=i>>1;j++) //尽量不重复计算的方法
count[i]+=count[j-1]*count[i-j]*2;
if(i&1!=0) count[i]+=count[i>>1]*count[i>>1];
}
/*
for(int i=2;i<=n;i++){
count[i]=0;
for(int j=1;j<=i;j++) //代码简洁的方法
count[i]+=count[j-1]*count[i-j];
}
*/
return count[n];
}
};