leetcode95题目传送门
leetcode96 不同二叉搜索树个数 题解
题目:给定一个整数 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
仔细分析,可以发现一个规律。首先我们每次新增加的数字大于之前的所有数字,
所以新增加的数字出现的位置只可能是:
根节点 或者 根节点的右孩子,右孩子的右孩子,右孩子的右孩子的右孩子等等,
总之一定是右边。其次,新数字所在位置原来的子树,
改为当前插入数字的左孩子即可,因为插入数字是最大的。
对于下边的解
2
/
1
然后增加 3
1.把 3 放到根节点
3
/
2
/
1
2. 把 3 放到根节点的右孩子
2
/ \
1 3
对于下边的解
1
\
2
然后增加 3
1.把 3 放到根节点
3
/
1
\
2
2. 把 3 放到根节点的右孩子,原来的子树作为 3 的左孩子
1
\
3
/
2
3. 把 3 放到根节点的右孩子的右孩子
1
\
2
\
3
以上就是根据 [ 1 2 ] 推出 [ 1 2 3 ] 的所有过程,可以写代码了。由于求当前的所有解只需要上一次的解,所有我们只需要两个 list,pre 保存上一次的所有解, cur 计算当前的所有解。
最后返回的List里面存的是每颗树的根节点root。
class Solution {
// 拷贝二叉树
TreeNode copyTree(TreeNode root) {
if (root == null) return null;
TreeNode newRoot = new TreeNode(root.val);
newRoot.left = copyTree(root.left);
newRoot.right = copyTree(root.right);
return newRoot;
}
public List<TreeNode> generateTrees(int n) {
List<TreeNode> pre = new ArrayList<>();
if (n == 0) return pre;
pre.add(null);
// 每次增加一个数字
for (int i = 1; i <= n; ++i) {
List<TreeNode> cur = new ArrayList<>();
//遍历之前的所有解
for (TreeNode root : pre) {
// 下面三行是i作为根节点,root作为它的左子树
TreeNode replaceRoot = new TreeNode(i);
replaceRoot.left = root;
cur.add(replaceRoot);
// 插入到右孩子,右孩子的右孩子...最多找 i - 1 次孩子
// 这次找到的右孩子之后,原来树的结构不能变,因为下一次j循环用的还是旧树
// 所以每一层j遍历都要完全拷贝旧树
for (int j = 0; j < i; ++j) {
TreeNode copyRoot = copyTree(root); //复制当前的树
TreeNode work = copyRoot; //找到要插入右孩子的位置
// 遍历 j 次找右孩子, k 是往右子树移动次数
// 移动 k 次, 可以 遍历 k+1 个节点
for (int k = 0; k < j; ++k) {
if (work == null) break;
else work = work.right;
}
//到达 null 提前结束
if (work == null) break;
//保存当前右孩子的位置的子树作为插入节点的左孩子
TreeNode tmpWorkRight = work.right;
TreeNode iNode = new TreeNode(i);
work.right = iNode; //右孩子是插入的节点
//插入节点的左孩子更新为插入位置之前的子树
iNode.left = tmpWorkRight;
cur.add(copyRoot);
}
}
pre = cur;
}
return pre;
}
}