zoukankan      html  css  js  c++  java
  • leetcode 不同的二叉搜索树-笛卡尔积与卡特兰数

      首先,我们假定求长度为 n 的数列可组成的二叉搜索树的数量为 G(n)。

      想办法将 G(n) 用其子问题表示,如果我们以第 i 个元素为根,则其左子树的数量为 G(i-1),右子树的数量为 G(n-i) 。那么以第 i 个元素为根的二叉搜索树的数量为 G(i-1) 与 G(n-i) 两个集合的笛卡尔积:G(i-1)*G(n-i)。

      想要覆盖全部解空间,我们必须将以每个元素为根的情况都计算出来,并求它们的和,那么状态转移方程即为:

      

       边界条件 G(0)=0 ;G(1)=1 ; 但是 G(0) 我们需要做特殊处理,对于我们的计算情景来说,如果一侧的二叉树种类为 0 ,那么总的种类应该是另一侧的种类,也就是说 G(0) 应当为 1。

      同时 n-i 需大于等于 0 ,也就是 n 需要大于等于 1。

      所以,计算 G(n) 依赖 G(0)、G(1) ... G(n-1) ,且 n >=1 。对该方程进行实现:

        public int numTrees(int n) {
            if (n == 0) {
                return 0;
            }
            int[] g = new int[n + 1];
            g[0] = 1;
            g[1] = 1;
            for (int i = 2; i <= n; i++) {
                for (int j = 1; j <= i; j++) {
                    g[i] += g[j - 1] * g[i - j];
                }
            }
            return g[n];
        }

      上面描述的 G(n) 函数被称为卡特兰数:

      通过卡特兰数公式进行计算,可以将时间复杂度降低到 O(N):

    public int numTrees(int n) {
        long C = 1;
        for (int i = 0; i < n; ++i) {
          C = C * 2 * (2 * i + 1) / (i + 2);
        }
        return (int) C;
      }

      将问题分解为子问题,用子问题的解表示原问题的解。也就是问题表示问题,用函数表示函数,可以帮助我们直接找到解决问题所需要的上层逻辑,也就是问题间的逻辑关系。从而屏蔽掉很多不需要的底层逻辑细节,得到最简洁干净的表示方式。

      

      

  • 相关阅读:
    23、Linux实操篇——RPM与YUM
    22、Linux实操篇——进程管理(重点)
    21、Linux实操篇——网络配置
    20、Linux实操篇——磁盘分区、挂载
    19、Linux实操篇——组管理和权限管理
    18、实操篇——实用指令
    17、实操篇——用户管理
    UVALive 2521 Game Prediction 题解
    UVALive 2517 Moving Object Recognition(模拟)
    UVALive 2324 Human Gene Functions(动态规划)
  • 原文地址:https://www.cnblogs.com/niuyourou/p/12798819.html
Copyright © 2011-2022 走看看