• 95. Unique Binary Search Trees II


    题目

    Given an integer n, generate all structurally unique BST's (binary search trees) that store values 1 ... n.

    Example:

    Input: 3
    Output:
    [
      [1,null,3,2],
      [3,2,null,1],
      [3,1,null,null,2],
      [2,1,3],
      [1,null,2,null,3]
    ]
    Explanation:
    The above output corresponds to the 5 unique BST's shown below:
    
       1         3     3      2      1
               /     /      /       
         3     2     1      1   3      2
        /     /                        
       2     1         2                 3

    思路

    记fn为1至n组成的BST的集合。对该BST,根的值有n种情况。对每一个根值i,左树为1至i-1,即问题fi-1。右树为i+1至n,即问题fn-i,但每个节点要+i。即

    fn = ∑ fi-1 * fn-i (i=1...n)

    注: 此处答案要求是一个List,所以*不代表数学的乘积而是将左右树做交叉结合

    代码

     1 class Solution {
     2     public List<TreeNode> generateTrees(int n) {
     3         List<TreeNode>[] dp = new List[n + 1];
     4         dp[0] = new ArrayList<>();
     5         if(n == 0) return dp[0];
     6         dp[0].add(null);
     7         
     8         for(int i = 1; i <= n; i++){
     9             dp[i] = new ArrayList<>();
    10             for(int j = 1; j <= i; j++){
    11                 int left = j - 1, right = i - j;
    12                 for(TreeNode leftTree : dp[left])
    13                     for(TreeNode rightTree : dp[right]){
    14                         TreeNode root = new TreeNode(j);
    15                         root.left = clone(leftTree, 0);
    16                         root.right = clone(rightTree, j);
    17                         dp[i].add(root);
    18                     }
    19             }
    20         }
    21         return dp[n];
    22     }
    23     
    24     private TreeNode clone(TreeNode x, int offset){
    25         if(x == null)
    26             return null;
    27         TreeNode result = new TreeNode(x.val + offset);
    28         result.left = clone(x.left, offset);
    29         result.right = clone(x.right, offset);
    30         return result;
    31     }
    32 }

    复杂度(大致分析)

    设问题n对应的List长度为ln,由于每次都从1到n开始填表,则问题n的时间复杂度Tn大致为

    Tn = 1*l1 + 2*l2 + ...+ n*ln   (1)

    其中乘以n的原因是:ln中的每一颗树都是通过克隆子问题的树形成的。对于一个n个节点的树,克隆的时间为O(n)。

    对于每一个ln,考虑到其左右子树的不同大小,又有

    l= ∑ lj-1 * ln-j (j=1...n)   (2)

    即l2 = l0*l1 + l1*l0, l3 = l0*l2 + l1*l1 + l2*l0,...

    n 0 1 2 3 4 5 6 ...
    ln 1 1 2 5 14 42 ... ...
    这是一个卡塔兰数(Catalan Number),我们只要知其结果即可。结果是ln = (2n)!/((n+1)!(n)!)。
     
    这个链接声称卡塔兰数的和满足
    SN204N9eπN3/2.
    SN204N9eπN3/2.

    我们的和里还有一个因子n(式1),大致可以确定Tn大概为O(4n/nk)的样子吧,至于k是几不会算(据上式,起码有k<3/2...)……

    实际上,卡塔兰数的渐进表示大致为

    与上述估算的Tn大致相同(最大的差别在于那个clone所耗费的因子n),也就是说dp算法本身比穷举法的时间复杂度差一点,拖了一点后腿……

    不过这个问题用穷举法确实没想到intuitive的算法,backtracking的话估计浪费更严重,dp应该算是比较简洁又复杂度还可以的算法……

  • 相关阅读:
    一步一步写数据结构(线索二叉树)
    Android studio 下JNI编程实例并生成so库
    IOS和Android音频开发总结
    IDEA常用快捷键
    Spring事务简介
    IDEA新建Springboot项目
    140201126杨鹏飞作业六
    140201126杨鹏飞作业三
    140201126杨鹏飞作业七
    自我介绍
  • 原文地址:https://www.cnblogs.com/mozi-song/p/9621587.html
Copyright © 2020-2023  润新知