【LeetCode】不同的二叉搜索树 [M](卡特兰数)

166 篇文章 0 订阅

96. 不同的二叉搜索树 - 力扣(LeetCode)

一、题目

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

示例 1:

输入:n = 3
输出:5

示例 2:

输入:n = 1
输出:1

提示:

  • 1 <= n <= 19

二、代码

class Solution {
    public int numTrees(int n) {
        return compute(n);
    }

    public int compute(int N) {
        // 过滤特殊值
        if (N < 0) {
            return 0;
        }
        if (N < 2) {
            return 1;
        }
        
        long a = 1;
        long b = 1;
        long c = 0;
        // 2n
        long limit = N << 1;
        // 1、计算c(2N, N) = b / a
        for (long j = 1, i = N + 1; j <= N && i <= limit; j++, i++) {
            // 计算a:从1累乘到n
            a *= j;
            // 计算b:从n+1一直累乘到2n  
            b *= i;

            // 求a和b的最大公因数,用来对a和b进行分数化简,避免在计算过程中溢出。
            // 如果这里不进行化简的话,当N比较大的时候就会出现数据溢出情况
            c = gcd(a, b);
            a /= c;
            b /= c; 
        }

        // 2、计算公式3的计算结果
        // 公式3:k(n)= c(2n, n) / (n + 1)
        // c(n, m) = n(n-1)...(n-m+1) / m!
        // b:2n * (2n - 1) * ... * (2n - n + 1)   也就是从n+1一直累乘到2n
        // a:1 * 2 * ... * (n - 1) * n   也就是从1一直累乘到n
        // c(2N, N) = b / a
        return (int) ((b / a) / (N + 1));
    }

    // 辗转相除法求最大公因数
    public long gcd(long a, long b) {
        long c = a % b;
        if (c != 0) {
            return gcd(b, c);
        } else {
            return b;
        }
    }
}

三、解题思路 

卡特兰数满足如下关系式:

k(0)= 1, k(1)= 1时,如果接下来的项满足:

k(n)= k(0)*k(n-1) + k(1)*k(n- 2) + ... + k(n- 2)*k(1) + k(n- 1)* k(0)

或者

k(n)= C(2n, n) - C(2n, n-1)

或者

k(n)= C(2n, n) / (n + 1)

就说这个表达式,满足卡特兰数。

总的来说,需要剖析出这道题的本质:

假设n个节点存在二叉排序树的个数是G(n),1为根节点,2为根节点,...,n为根节点,当1为根节点时,其左子树节点个数为0,右子树节点个数为n-1,同理当2为根节点时,其左子树节点个数为1,右子树节点为n-2,所以可得G(n) = G(0)*G(n-1)+G(1)*(n-2)+...+G(n-1)*G(0)。

明白了这道题的本质,发现了这个计算式子,就马上意识到这是一个卡特兰数的题目,直接用卡特兰数的计算公式计算结果即可。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值