一、需求
- 给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?
示例:
输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树:1 3 3 2 1
\ / / / \ \
3 2 1 1 3 2
/ / \ \
2 1 2 3
二、动态规划法
2.1 思路分析
- 当求解问题的方案总数时往往能够联想到动态规划,而动态规划是能够将原问题分解为多个子问题,因此能不能使用动态规划需要分析该问题能否分解为子问题;
- 现在已知就是序列[1,2,3,...,n],我们假设以 i (1<=i<=n) 为根节点构造BST,那么其左子树为[1,...,i-1],其右子树为[i+1,...,n],而左右子树的构建可以按照同样的方式递归构建;
- 因此,原问题就分解成了两个规模较小的子问题,而且子问题的解是可以复用的,因此可以使用动态规划求解;
- 定义状态:①G(n)表示长度为 n 的序列能构成的不同二叉搜索树的个数;②F(i,n)表示以 i为根、序列长度为 n 的不同二叉搜索树个数(1≤i≤n)。
- 具体的推导过程就看一下这里吧:https://leetcode-cn.com/problems/unique-binary-search-trees/solution/bu-tong-de-er-cha-sou-suo-shu-by-leetcode-solution/
- 对公式的解释:,表示以 i 为根,其左子树对应的BST的数量,表示以 i 为根,其右子树对应的BST的数量,其对应卡特兰数公式,这个公式也有对应的实现算法;
2.2 代码实现
class Solution {
public int numTrees(int n) {
int[] G = new int[n+1];
G[0] = 1;
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];
}
}
2.3 复杂度分析
- 时间复杂度为;
- 空间复杂度为O(N);
三、数学法
3.1 思路分析
- 数学中有专门用于计算卡特兰数的公式:,;
3.2 代码实现
class Solution {
public int numTrees(int n) {
// 提示:我们在这里需要用 long 类型防止计算过程中的溢出
long C = 1;
for (int i = 0; i < n; ++i) {
C = C * 2 * (2 * i + 1) / (i + 2);
}
return (int) C;
}
}
3.3 复杂度分析
- 时间复杂度为O(N);
- 空间复杂度为O(1);
四、学习地址
作者:LeetCode-Solution