不同二叉搜索树Ⅱ学习笔记
题目描述:
给定一个整数 n,生成所有由 1 … n 为节点所组成的 二叉搜索树
示例:
输入: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
/**
* 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;
* }
* }
*/
解题思路:
二叉搜索树关键的性质是根节点的值大于左子树所有节点的值,小于右子树所有节点的值,且左子树和右子树也同样为二叉搜索树。因此在生成所有可行的二叉搜索树的时候,假设当前序列长度为 n,如果我们枚举根节点的值为 i,那么根据二叉搜索树的性质我们可以知道左子树的节点值的集合为 [1 \ldots i-1][1…i−1],右子树的节点值的集合为 [i+1 \ldots n][i+1…n]。而左子树和右子树的生成相较于原问题是一个序列长度缩小的子问题,因此我们可以想到用递归的方法来解决这道题目。
我们定义 generateTrees(start, end) 函数表示当前值的集合为 [\textit{start},\textit{end}][start,end],返回序列 [\textit{start},\textit{end}][start,end] 生成的所有可行的二叉搜索树。按照上文的思路,我们考虑枚举 [\textit{start},\textit{end}][start,end] 中的值 ii 为当前二叉搜索树的根,那么序列划分为了 [\textit{start},i-1][start,i−1] 和 [i+1,\textit{end}][i+1,end] 两部分。我们递归调用这两部分,即 generateTrees(start, i - 1) 和 generateTrees(i + 1, end),获得所有可行的左子树和可行的右子树,那么最后一步我们只要从可行左子树集合中选一棵,再从可行右子树集合中选一棵拼接到根节点上,并将生成的二叉搜索树放入答案数组即可。
递归的入口即为 generateTrees(1, n),出口为当 \textit{start}>\textit{end}start>end 的时候,当前二叉搜索树为空,返回空节点即可
class Solution {
public List<TreeNode> generateTrees(int n) {
if (n == 0) {
return new LinkedList<TreeNode>();
}
return generateTrees(1, n);
}
public List<TreeNode> generateTrees(int start, int end) {
List<TreeNode> allTrees = new LinkedList<TreeNode>();
if (start > end) {
allTrees.add(null);
return allTrees;
}
//递归方法的出口
//注意start = end也可以
// 枚举可行根节点 重点
for (int i = start; i <= end; i++) {
//注意这里的循环是从start开始的
// 获得所有可行的左子树集合
List<TreeNode> leftTrees = generateTrees(start, i - 1);
// 获得所有可行的右子树集合
List<TreeNode> rightTrees = generateTrees(i + 1, end);
// 从左子树集合中选出一棵左子树,
// 从右子树集合中选出一棵右子树,拼接到根节点上
for (TreeNode left : leftTrees) {
for (TreeNode right : rightTrees) {
TreeNode currTree = new TreeNode(i);
//创建根节点
currTree.left = left;
currTree.right = right;
allTrees.add(currTree);
}
}
}
return allTrees;
}
}
//作者:LeetCode-Solution
//链接:https://leetcode-cn.com/problems/unique-binary-search-trees-ii/solution/bu-tong-de-er-cha-sou-suo-shu-ii-by-leetcode-solut/
//来源:力扣(LeetCode)
总结
如何理解递归,要理解一个递归方法,就得把一个复杂的问题分成许多简单问题。如题要解决二叉搜索树,摆在面前的复杂问题有:树有多少种结构,每种结构的数字是多少。首先我们得分析二叉树结构,右子树大于根子树,左子树小于根子数。然后我们考虑这个问题最简单的情况。n=1,无论如何变化只有一种情况。n=2,可以很容易看出有两种情况。n=3,我们可以拆分成n=1和n=2两种情况。根据二叉树规律我们可以确定根结点然后根据根结点拆分为左右两部分,然后根据n的大小迭代左右分支的n的大小,n左=0,n右=2…
综上,我们可以得到解决这个问题的递归规律了。通过循环迭代i确定1到n作为根结点的情况,每一个分支又是1到i,i到n继续迭代,迭代到最后就是n到n…逐级返回形成List,然后通过循环添加到根节点。最后形成完整的二叉树结构。