95. Unique Binary Search Trees II [Medium]

本文介绍了一种利用动态规划解决生成所有可能的唯一二叉搜索树(BST)的问题的方法。通过对不同节点数量的BST进行递归构造,实现了对所有形态的覆盖。文章详细解释了如何通过递归组合左右子树来生成新的BST,并强调了右子树需要通过偏移值进行深拷贝的重要性。
摘要由CSDN通过智能技术生成

很复杂的一道题,做题时状态好,加上刚做了普通Unique Binary Search Trees动态规划的解法还热着,很快就找到了以下的思路

但这道题比只要求数量的还是难很多,写起来很复杂,花了很久时间 

【本题注意】

本题中List<TreeNode>存储的每一个TreeNode,都是一颗树的根节点,代表一整棵树

我们往一个list里面加node的时候,也要将它构造成BST的根节点

【自己的代码思路】

动态规划为基础思想,用dp[i]存储i个节点能组成的所有BST的根节点

计算dp[i]的方法是循环将1~i的任意节点k确定为根节点,然后组合dp[k - 1]和dp[i - k]中存储的左右子树形态,得到dp[i]的所有树

这里还需要注意的是:

右子树的节点值是大于dp[i - k]中树的节点值的,所以dp[i - k]中的树不能直接作为右子树,而是必须拷贝每一棵dp[i - k]中树的形态,并将值加上一个offset,创建得到右子树

左子树是可以直接使用dp[k - 1]的

/**
 * 自己的代码
 * (最开始深拷贝是复制来的,因为这题代码量太大了,怕思路错了白费太多功夫,又怕深拷贝写错了加大debug难度,通过之后自己写了深拷贝)
 * Runtime: 1 ms, faster than 92.36%
 * Memory Usage: 39.1 MB, less than 91.95%
 */
class Solution {
    public List<TreeNode> generateTrees(int n) {
        List<TreeNode>[] dp = new LinkedList[n + 1];
        dp[0] = new LinkedList<>();
        dp[0].add(null);
        for (int i = 1; i <= n; i++) {
            dp[i] = new LinkedList<>();
            for (int j = 0; j < i; j++)
                newList(dp[j], dp[i - 1 - j], j + 1, dp[i]);
        }
        return dp[n];
    }

    // 将各个左子树、右子树组合成以值为val的节点为根节点的树,加入dp[i],循环完成得到dp[i]
    private void newList(List<TreeNode> left, List<TreeNode> right, int val, List<TreeNode> curr) { 
        for (TreeNode tl : left) 
             for (TreeNode tr : right) {
                 TreeNode trCopy = tr == null ? null : copyTree(tr, val); // 右子树的应该有的节点值比dp中对应树的大,所以需要进行深拷贝生成一颗val = val + offset的新树作为右子树;左子树不用
                 TreeNode nodeJ = new TreeNode(val, tl, trCopy);
                 curr.add(nodeJ);
             }
    }

    // 深拷贝一棵和root一样的树,原树的节点val + offset = 新树的节点val
    private TreeNode copyTree(TreeNode n, int offset) { 
        if (n == null)
            return null;
        TreeNode node = new TreeNode(n.val + offset);
        node.left = copyTree(n.left, offset);
        node.right = copyTree(n.right, offset);
        return node;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值