echo

任生命穿梭 时间的角落

0%

不同的二叉搜索树II

95. 不同的二叉搜索树 II

给定一个整数 n,生成所有由 1 … n 为节点所组成的 二叉搜索树

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
输入:3
输出:
[
[1,null,3,2],
[3,2,null,1],
[3,1,null,null,2],
[2,1,3],
[1,null,2,null,3]
]
解释:
以上的输出对应以下 5 种不同结构的二叉搜索树:

1 3 3 2 1
\ / / / \ \
3 2 1 1 3 2
/ / \ \
2 1 2 3

提示:

  • 0 <= n <= 8

我们枚举根结点的值为 i ,根据 BST 的性质,我们可以知道左子树的结点值集合为 [1 … i - 1],右子树的结点值集合为 [i + 1 … n]。我们可以使用递归来建立子树。

我们定义 generateTrees(start, end)函数表示当前值的集合为 [start, end],返回序列 [start, end]生成的所有可行的 BST。我们在 [start, end] 中枚举根结点 i ,将序列分为 [start, i - 1] 和 [i + 1, end] 递归地调用 generateTrees 函数。我们获得了所有的可行的右子树,最后一步,我们从左右子树集合中任选两课拼接到根结点上。

当 start > end 时递归,BST 为空,返回空结点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<TreeNode> generateTrees(int n) {
if(n == 0){
return new LinkedList<TreeNode>();
}

return generateTrees(1, n);
}

List<TreeNode> generateTrees(int start, int end){
List<TreeNode> allTrees = new LinkedList<>();
if(start > end){
allTrees.add(null);
return allTrees;
}
//枚举根结点
for(int i = start; i <= end; i++){
//得到左子树结点
List<TreeNode> leftTrees = generateTrees(start, i - 1);
//得到右子树结点
List<TreeNode> rightTrees = generateTrees(i + 1, end);
//从左右子树结点集合中拿出两个结点连接到根结点
for(TreeNode left : leftTrees){
for(TreeNode right : rightTrees){
TreeNode curTree = new TreeNode(i);
curTree.left = left;
curTree.right = right;
allTrees.add(curTree);
}
}
}
return allTrees;
}

}

最后的结果存储了许多 BST 的根结点,我们以 n = 5, i = 3 为例来解释:

以 3 为根结点,左子树结点集合 为指向 1、2 的两个结点,右子树结点为指向 4、5 的两个结点,左右各取一个结点,新建一个根结点,生成 4 棵以 3 为根结点的 BST。

image-20200721114003250