不同的二叉搜索树
题目描述:给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?
题目分析:
二叉搜索树的性质:
1. 二叉搜索树要求有一个根节点;
2. 根节点左子树的所有节点值全部<=根节点值;
3. 根节点右子树的所有节点值全部>=根节点值;
求解分析:
穷举所有的二叉树显然过于复杂,所以考虑递归的思想,即对于1<=i<=n为节点,每一个节点i都对应着一系列的二叉搜索树。
设以[1-n]为节点组成的二叉搜索树的个数为G(n),则当根节点为i时(1<=i<=n),左子树的可能性有G(i-1)种, 右子树的可能性有G(n-i)种,所以得到递推公式:G(n) = ∑ i = 1 n \sum_{i=1}^n ∑i=1n(G(i-1)*G(n-i))
如果单纯的按照递推公式来用递归求解此题,则时间复杂度太大,代码如下:
int numTrees(int n){
if((n == 0)||(n == 1))
return 1;
int sum = 0;
for(int i =1;i<=n;i++)
sum += numTrees(i-1)*numTrees(n-i);
return sum;
}
很显然,渐进分析后,发现以上算法的时间复杂度为θ(3^n),需要换一种算法。
新算法分析:当元素从[1-n]时,或许求和过程有点抽象,不妨考虑具体的数值,例如考虑n=3,即元素从[1-3]:
G(3) = G(0)*G(2)+G(1)*G(1)+G(2)*G(0)
G(2) = G(0)*G(1)+G(1)*G(0)
G(1) = 1
G(0) = 1
由此可见:要想求G(3),就要知道G(0),G(1),G(2),要想求G(2),就要知道G(0),G(1),所以要想求解G(n),需要知道G(0)…G(n-1),所以我们可以从G(0)开始,一直递增的顺序向上求解到G(n),不妨用一个数组来存储每个G(i)的值,特别的G(0) = 1,G(1) = 1,代码如下:
int numTrees(int n){
vector<int> G(n,0);
G[0] = G[1] = 1;
for(int i = 2; i<=n; i++)
for(int j = 1; j<=i; j++)
G[i] += G[j-1]*G[i-j];
return G[n];
}
该算法的时间复杂度为θ(n^2) 。