Leetcode95. Unique Binary Search Trees II and I

23 篇文章 0 订阅
15 篇文章 0 订阅

分析一:

动态规划问题

这道题目要求给定一个数n,有多少种二叉树排列方式,用来存储1到n。
刚开始拿到这题的时候,完全不知道如何下手,但考虑到二叉树的性质,对于任意以i为根节点的二叉树,它的左子树的值一定小于i,也就是[0, i - 1]区间,而右子树的值一定大于i,也就是[i + 1, n]。假设左子树有m种排列方式,而右子树有n种,则对于i为根节点的二叉树总的排列方式就是m x n。

我们使用dp[i]表示i个节点下面二叉树的排列个数,
那么dp方程为:

dp[i] = sum(dp[k] * dp[i - k -1]) 0 <= k < i

全排列的方式来处理这个过程,当这个过程
当数组为 1,2,3,…,n时,基于以下原则的构建的BST树具有唯一性: \textbf{以i为根节点的树,其左子树由[1, i-1]构成, 其右子树由[i+1, n]构成。}
定义f(i)为以[1,i]能产生的Unique Binary Search Tree的数目,则
如果数组为空,毫无疑问,只有一种BST,即空树,f(0)=1。
如果数组仅有一个元素{1},只有一种BST,单个节点,f(1)=1。
如果数组有两个元素{1,2}, 那么有如下两种可能
1 2
\ /
2 1
f(2) = f(0) * f(1) f(2)=f(0)∗f(1) , when 1 as root
+ f(1) * f(0) +f(1)∗f(0) , when 2 as root
再看一看3个元素的数组,可以发现BST的取值方式如下:
f(3) = f(0) * f(2) f(3)=f(0)∗f(2) , when 1 as root
+ f(1) * f(1) , when 2 as root
+ f(2) * f(0) , when 3 as root

class Solution {
    public int numTrees(int n) {
      int [] dp=new int [n+1];

      dp[0] = 1;
      dp[1] = 1;

     for(int i=2;i<=n;i++){

         //以哪个数据为根节点,i代表n,表示n的代表, 逐渐以0
         for(int j=0;j<i;j++){
             //j代表右边节点的个数,即是比i小的数据有j个,
           //   i-j-1代表左边的节点数据
             //再加上根节点数据,一共则有i个数据情况
             dp[i] += dp[j] * dp[i-j-1];
         }
     }
    return dp[n];
    }
}

至此,问题划归为一维动态规划。
进阶问题:

分析二

这道题目采用二分法和递归方法·解决, 1<=i<=n,
i代表root, [1,i-1] 为有节点 [i, n] 为右节点,然后左右两边又不断分治的方法解决
分而治之用于归并排序

从上到下面分治,然后从下面到上面合并结果流程,

result 保存的的就死可能的中间结果, 左右子树的可能性问题
类似于这种方法就是
代码书写流程

  1. 递归递归判断条件,递归的出口文件
  2. 对原始问题进行处理,处理左边,处理右边
  3. 合并两边结果
  4. 从宏观上把握这种情况

归并排序对算法:
分治: 从中间开始分开,数组元素个数大于两个数,就分开
merge :合并两边元素个数情况
归并排序的过程图
分治树过程图

class Solution {
    public List<TreeNode> generateTrees(int n){
        if(n==0) return new ArrayList<>();
        return gen(1,n);
    }
    private List<TreeNode> gen(int start,int end){
        //result 存储的不是最终的结果,存储的是中间可能结果
        //比如[1,0], 那么这边的字树为0个节点,也就是空节点,如果是[1,1]这样的情况,那么这种情况就是单独一个节点的情况
        //分治法从上到下面划分,结果从下面到上面开始返回,
        List<TreeNode> result = new ArrayList<>();
        if(start>end) {
            result.add(null);
            return result;
        }
        if(start==end)
        {
            result.add(new TreeNode(start));
            return result;
        }

        for(int i=start;i<=end;i++){

        List<TreeNode> left = gen(start,i-1);
        List<TreeNode> right = gen(i+1,end);

            for(TreeNode lnode: left){
                for(TreeNode rnode:right){
                    TreeNode root =new TreeNode(i);
                    root.left = lnode;
                    root.right = rnode;
                    result.add(root);
                }
            }
        }
        return result;
    }

}

}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值