题目来源:力扣
题目介绍:
给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?
示例:
输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树.
审题:
考虑对于从 i i i到 j j j的节点序列,我们可以选择 i i i到 j j j的任意一个值作为二叉搜索树根节点,假设选择 k k k作为根节点,则此时左子树的有节点序列 i i i到 k − 1 k-1 k−1构成,右子树由节点 k + 1 k+1 k+1到 j j j构成.假设我们节点序列 i i i到 k − 1 k-1 k−1共有 m m m种不同形式的二叉搜索树形式,节点序列 k + 1 k+1 k+1到 j j j共有 n n n种不同形式的二叉搜索树,则我们选择 k k k作为根节点,可以得到 m n mn mn种不同的二叉搜索树形式.而节点序列 i i i到 j j j可能构成的二叉搜索树个数选择不同根节点 k k k得到的二叉树个数之和.
事实上,我们可以发现,该问题并不涉及最优性问题,因为为了计算所有可能的二叉树种类,我们需要计算每一个可能的根节点位置选择方案下,所可能产生的二叉搜索树个数,在这一步中,并不存在最优选择,而是将所有选择结果相加.但由于子问题存在重叠,因此我们仍然可以考虑使用动态规划算法解决该问题.
为了求解长度为
k
k
k的节点序列可能产生的二叉搜索树总个数,我们需要已知所有长度小于
k
k
k的节点序列所可能产生的二叉搜索树个数,此时的基础情形便是长度为1或长度为0的情形.如果当前节点序列长度为0或1,则此时的二叉搜索树只有一种形式.
我们使用二维数组存储每一状态下,总方案.在该问题中,状态包括节点序列的起点与终点
S
[
i
[
j
]
S[i[j]
S[i[j]表示节点序列
i
,
i
+
1
,
.
.
.
j
−
1
i, i+1, ...j-1
i,i+1,...j−1所能构长的二叉搜索树个数.
以上是我一开始面对该问题时所提出的方法, 后面我进一步思考发现,二叉搜索树的可能个数与当前节点序列的值并无关系,仅与当前节点序列的长度有关.因此,我们可以进一步简化动态规划算法. 此时,当前的状态变量为节点序列的长度
l
l
l, 我们可以在每一步选择左子树的大小,其取值范围从
0
0
0到
l
−
1
l-1
l−1. 我们使用一维数组S存储当前状态下二叉搜索树可能个数, 我们可以得到如下状态转移方程:
S
[
l
]
=
s
u
m
{
S
[
l
e
f
t
]
+
S
[
l
−
l
e
f
t
−
1
]
,
0
≤
l
e
f
t
≤
l
−
1
}
S[l] = sum\{S[left] + S[l-left-1] , 0 \leq left \leq l-1 \}
S[l]=sum{S[left]+S[l−left−1],0≤left≤l−1}
java算法:
方法一
class Solution {
public int numTrees(int n) {
//S[i][j]表示以i...j-1为节点组成的二叉搜索树共有多少种
//如果根节点选为k, 则S[i][k] + S[k+1][j]
int[][] S = new int[n+2][n+3];
//basecase
for(int i = 1; i < n+2; i++){
S[i][i] = 1;
S[i][i+1] = 1;
}
//如果计算长度为k的节点所能组成的二叉树, 我们应当计算确定所有长度小于k的节点序列所能组成的二叉树
for(int len = 2; len <= n; len++){
for(int left = 1; left <= n-len+1; left++ ){
int right = left+len;
int total = 0;
for(int root = left; root < right; root++){
total += (S[left][root] * S[root+1][right]);
}
S[left][right] = total;
}
}
return S[1][n+1];
}
}
方法二:
class Solution {
public int numTrees(int n) {
int[] S = new int[n+1];
S[0] = 1;
S[1] = 1;
//如果计算长度为k的节点所能组成的二叉树, 我们应当计算确定所有长度小于k的节点序列所能组成的二叉树
for(int len = 2; len <= n; len++){
int total = 0;
for(int leftSize = 0; leftSize < len; leftSize++){
total += S[leftSize] * S[len-leftSize-1];
}
S[len] = total;
}
return S[n];
}
}