leetcode95. 不同的二叉搜索树 II

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;
    }

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值