题意
给定一个数n,求有n个节点的BST的数目(节点的值依次是1到n)。
思路
就一Catalan数。
我们求解有3种方法:
- Cn=1n+1(2nn)
- Cn+1=2(2n+1)n+2CnC0=1
- dp:同Catalan数的公式
证明
首先,Catalan数的公式:Cn+1=∑i=0nCiCn−i
然后,我们来这样考虑,一个有n + 1个节点的BST,假设我们根节点的值为i + 1,那么,小于i + 1的所有值(1到i)都在左子树,大于i + 1的所有值都在右子树(n - i个),并且,每个子树都为BST。
我们设有i个节点的BST数目为pi,那么,我们假设我们以i+1作为根节点的BST数目为pi⋅pn−i。
并且,我们可以用0到n这n + 1个数作为根节点,此时,我们有n个节点的所有BST数目为pn+1=p0⋅pn+p1⋅pn−1+...+pn⋅p0=∑i=0npi⋅pn−i,即Catalan数。
细节
解法1需要注意会爆long long,需要__int128
解法2会爆int需要long long
代码
//algorithm 1
#define LL __int128
class Solution {
public:
int numTrees(int n) {
LL res1 = 1, res2 = 1;
for (LL i = n + 2; i <= (LL)2 * n; i++) {res1 *= i;}
for (LL i = 1; i <= (LL)n; i++) res2 *= i;
return res1 / res2;
}
};
//algorithm 2
#define LL long long
class Solution {
public:
int numTrees(int n) {
LL x = 1; // init, x = C0
for (int i = 1; i <= n; i++) {
x = (LL)(2 * (2 * i - 1) * x) / (i + 1);
}
return x;
}
};
//algorithm 3
const int maxn = 30;
int d[maxn];
class Solution {
public:
int dfs(int n) {
if (d[n] != -1) return d[n];
d[n] = 0;
for (int k = 0; k < n; k++) {
d[n] += (dfs(k) * dfs(n - 1 - k));
}
return d[n];
}
int numTrees(int n) {
memset(d, -1, sizeof(d));
d[0] = 1;
return dfs(n);
}
};