力扣第九十六题-不同的二叉搜索树

「这是我参与11月更文挑战的第16天,活动详情查看:2021最后一次更文挑战

前言

力扣第九十六题 不同的二叉搜索树 如下所示:

给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。

示例 1:

输入: n = 3
输出: 5
复制代码

一、思路

这一题比上一题不同的是:只关心二叉搜素树的种树,而不关系树的节点了

所以一开始我的思路也是用递归来做的,去除了保留路径的部分,仅得到左孩子的个数和右孩子的个数即可。7代码如下所示:

public int dfs(int start, int end) {
    int ret = 0;
    if (start > end) {
        return 1;
    }
    // 枚举可行根节点
    for (int i = start; i <= end; i++) {
        // 找到所有的左子树
        int left = dfs(start, i - 1);

        // 找到所有的右子树
        int right = dfs(i + 1, end);
        ret += left * right;
    }
    return ret;
}
复制代码

但是很可惜,在 n=18 时会提示超出时间限制!

那既然不能用 递归 来自顶向下,那就只能使用 动态规划 来实现 自底向上 了。

首先我们先看一下 递归 中调用的地方,我们发现在递归中一直在求 1 ~ i-1i+1 ~ n 左孩子和右孩子个数。

我们不妨设 dp[i] 为长度为 i 的不同二叉搜索树的个数。

可以有 dp[n] = dp[0]dp[n-1] + dp[1]dp[n-2] + dp[2]dp[n-3] + ... + dp[n-1]dp[0]

公式解释:
因为 dp[n] 就是选择 1 ~ n 中的某一个元素 i 为根,再将 1 ~ i-1 中的元素作为左孩子, i+1 ~ n 中的元素作为右孩子。
dp[0]dp[n-1] 就表示选择了第一个元素作为根有多少种结果。
此外,因为二叉搜索树的特殊性。对于 1, 2, 31, 2, 4 组成的二叉搜索树的种数是相同的。所以我们在公式中可以忽略元素的值,而只关注元素的个数,因为相同元素个数组成的二叉搜索树的种树是相同的。

二、实现

实现代码

实现代码与思路中保持一致

    public int numTrees(int n) {
        int[] dp = new int[n +1];
        dp[0] = dp[1] = 1;  // 0个和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];
    }
复制代码

测试代码

    public static void main(String[] args) {
        int ret = new Number96().numTrees(3);
        System.out.println(ret);
    }
复制代码

结果

image.png

三、总结

感谢看到最后,非常荣幸能够帮助到你~♥

如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~

猜你喜欢

转载自juejin.im/post/7031160547441967112
今日推荐