二叉树的个数
描述
已知一棵节点个数为 n 的二叉树的中序遍历单调递增, 求该二叉树能能有多少种树形, 输出答案对 109 +7 取模
数据范围:1≤n≤3000
示例1
输入:
1
输出:
1
示例2
输入:
2
输出:
2
示例3
输入:
4
输出:
14
题解1
时间复杂度:
O
(
N
2
)
O(N^2)
O(N2)
空间复杂度:
O
(
N
)
O(N)
O(N)
计
f
(
n
)
f(n)
f(n) 表示节点数为
n
n
n 的所有二叉树的形状数。显然
f
(
0
)
=
1
,
f
(
1
)
=
1
f(0) = 1, f(1) = 1
f(0)=1,f(1)=1,
f
(
2
)
=
2
f(2) = 2
f(2)=2。
当树的节点为 3 时,我们以根节点的左右子树的节点数量求解,可分为:
- 左子树2节点,右子树0节点;得到的情况数为 f ( 2 ) ∗ f ( 0 ) f(2)*f(0) f(2)∗f(0)
- 左子树1节点,右子树1节点;得到的情况数为 f ( 1 ) ∗ f ( 1 ) f(1)*f(1) f(1)∗f(1)
- 左子树0节点,右子树2节点;得到的情况数为
f
(
0
)
∗
f
(
2
)
f(0)*f(2)
f(0)∗f(2)
一般地: f ( n ) = ∑ i = 0 n − 1 f ( i ) ∗ f ( n − i − 1 ) f(n) = \sum_{i=0}^{n-1} f(i)*f(n-i-1) f(n)=∑i=0n−1f(i)∗f(n−i−1)。
代码
#include <bits/stdc++.h>
using namespace std;
long long f[3003];
long long mod = 1000000007;
long long numberOfTree(int n) {
memset(f, 0, sizeof f);
f[0] = 1ll;
f[1] = 1ll;
f[2] = 2ll;
for(int num = 3;num <=n; num++){
long long ans = 0;
for(int i = 0;i<num;i++){
ans = (ans + f[i]*f[num-i-1]%mod) % mod;
}
f[num] = ans % mod;
}
return f[n];
}
int main(){
int n;
cin>>n;
long long ans = numberOfTree(n);
cout<<ans;
return 0;
}
题解2
时间复杂度:
O
(
N
)
O(N)
O(N)
空间复杂度:
O
(
1
)
O(1)
O(1)
如果你了解 卡塔兰数 的话,你就会发现我们的结果就是 卡塔兰数。
他的递推关系式为:
f
(
n
+
1
)
=
f
(
n
)
∗
2
(
2
n
+
1
)
n
+
2
,
n
>
=
0
,
f
(
0
)
=
1
f(n+1) = f(n)*\frac{2(2n+1)}{n+2}, n>=0, f(0) = 1
f(n+1)=f(n)∗n+22(2n+1),n>=0,f(0)=1。
由于数据较大,我们又要取模还有除法,我么需要使用逆元,即为
i
n
v
(
N
)
inv(N)
inv(N)。
#include<bits/stdc++.h>
using namespace std;
const static long long MOD = 1000000007;
int numberOfTree(int n) {
std::vector<long long> arr(n + 1), inv(n + 2);
arr[0] = arr[1] = 1;
inv[1] = 1;
inv[2] = MOD - MOD / 2;
for (int i = 2; i <= n; ++i) {
inv[i + 1] = (MOD - MOD / (i + 1)) * inv[MOD % (i + 1)] % MOD;
arr[i] = arr[i - 1] * (4 * i - 2) % MOD * inv[i + 1] % MOD;
}
return arr.back();
}
int main(){
int n;
cin>>n;
long long ans = numberOfTree(n);
cout<<ans;
return 0;
}