每日一题——不同的二叉搜索树

菜鸡每日一题系列打卡96

每天一道算法题目 

小伙伴们一起留言打卡

坚持就是胜利,我们一起努力!

题目描述(引自LeetCode)

给定一个整数n,求以1 ... n为节点组成的二叉搜索树有多少种?

示例:


输入: 3


输出: 5


解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树:


   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

题目分析

这是上一道题目的简化版,我们在上一题中提到了卡特兰数的概念,这道题目其实就是求取的卡特兰数,但为了提供更多思路,菜鸡将采取两种方式进行求解。

  • 第一种是我们经常使用的动态规划。

  • 首先,我们记以i(1 <= i <= n)为根的二叉搜索树为F(i, n),记二叉搜索树的总数为G(n),则

    而考虑以i为根的二叉搜索树,其左子树必定以j(1 <= j < i)为根,其右子树必定以k(i < k <= n)为根。因此,以i为根的二叉搜索树,其左子树的总数为G(i - 1),其右子树的总数为G(n - i)。从而有

    综合上述两条等式,我们可以得到

    因此,只需要以dp[]数组记录G的值并进行计算即可。

  • 第二种是上文提到的卡特兰数计算。

    其实,这种方法可以由动态规划的递推式推演而来,我们可以得到,对n > 0,有

    从而可以直接按照上述公式进行计算,得到结果。

代码实现

// 动态规划
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++) {
            for (int j = 1; j <= i; j++) {
                dp[i] += dp[j - 1] * dp[i - j];
            }
        }
        return dp[n];
    }


}
// 卡特兰数
class Solution {


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


}

代码分析

对代码进行分析,动态规划的时间复杂度为O(n^2),空间复杂度为O(n);卡特兰数公式的时间复杂度为O(n),空间复杂度为O(1)。

执行结果

每日一题——不同的二叉搜索树_第1张图片

动态规划的执行结果

每日一题——不同的二叉搜索树_第2张图片

卡特兰数的执行结果

学习 | 工作 | 分享

????长按关注“有理想的菜鸡

只有你想不到,没有你学不到

你可能感兴趣的:(算法)