二叉树的个数

给定节点数n的二叉树,如果其中序遍历是单调递增的,文章探讨了这类二叉树可能的形状数量。提供了两种解决方案,一种基于动态规划,时间复杂度为O(N^2),另一种利用卡塔兰数的递推关系,时间复杂度为O(N)。并给出了相应的C++代码实现。
摘要由CSDN通过智能技术生成

二叉树的个数

描述

已知一棵节点个数为 n 的二叉树的中序遍历单调递增, 求该二叉树能能有多少种树形, 输出答案对 109 +7 取模

数据范围:1≤n≤3000

示例1

输入:

1

输出:

1

示例2

输入:

2

输出:

2

示例3

输入:

4

输出:

14

题解1

时间复杂度: O ( N 2 ) O(N^2) O(N2)
空间复杂度: O ( N ) O(N) O(N)

f ( n ) f(n) f(n) 表示节点数为 n n n 的所有二叉树的形状数。显然 f ( 0 ) = 1 , f ( 1 ) = 1 f(0) = 1, f(1) = 1 f(0)=1,f(1)=1, f ( 2 ) = 2 f(2) = 2 f(2)=2
当树的节点为 3 时,我们以根节点的左右子树的节点数量求解,可分为:

  • 左子树2节点,右子树0节点;得到的情况数为 f ( 2 ) ∗ f ( 0 ) f(2)*f(0) f(2)f(0)
  • 左子树1节点,右子树1节点;得到的情况数为 f ( 1 ) ∗ f ( 1 ) f(1)*f(1) f(1)f(1)
  • 左子树0节点,右子树2节点;得到的情况数为 f ( 0 ) ∗ f ( 2 ) f(0)*f(2) f(0)f(2)
    一般地: f ( n ) = ∑ i = 0 n − 1 f ( i ) ∗ f ( n − i − 1 ) f(n) = \sum_{i=0}^{n-1} f(i)*f(n-i-1) f(n)=i=0n1f(i)f(ni1)

代码


#include <bits/stdc++.h>
using namespace std;

long long f[3003];
long long mod = 1000000007;

long long numberOfTree(int n) {
    memset(f, 0, sizeof f);
    f[0] = 1ll;
    f[1] = 1ll;
    f[2] = 2ll;
    for(int num = 3;num <=n; num++){
        long long ans = 0;
        for(int i = 0;i<num;i++){
            ans = (ans + f[i]*f[num-i-1]%mod) % mod;
        }
        f[num] = ans % mod;
    }
    return f[n];
}

int main(){
    int n;
    cin>>n;
    long long ans = numberOfTree(n);
    cout<<ans;
    return 0;
}

题解2

时间复杂度: O ( N ) O(N) O(N)
空间复杂度: O ( 1 ) O(1) O(1)

如果你了解 卡塔兰数 的话,你就会发现我们的结果就是 卡塔兰数。
他的递推关系式为: f ( n + 1 ) = f ( n ) ∗ 2 ( 2 n + 1 ) n + 2 , n > = 0 , f ( 0 ) = 1 f(n+1) = f(n)*\frac{2(2n+1)}{n+2}, n>=0, f(0) = 1 f(n+1)=f(n)n+22(2n+1),n>=0,f(0)=1
由于数据较大,我们又要取模还有除法,我么需要使用逆元,即为 i n v ( N ) inv(N) inv(N)

#include<bits/stdc++.h>
using namespace std;

const static long long MOD = 1000000007; 

int numberOfTree(int n) {

    std::vector<long long> arr(n + 1), inv(n + 2);
    arr[0] = arr[1] = 1;
    inv[1] = 1;
    inv[2] = MOD - MOD / 2;
    for (int i = 2; i <= n; ++i) {
        inv[i + 1] = (MOD - MOD / (i + 1)) * inv[MOD % (i + 1)] % MOD;
        arr[i] = arr[i - 1] * (4 * i - 2) % MOD * inv[i + 1] % MOD;
    }
    return arr.back();
}

int main(){
    int n;
    cin>>n;
    long long ans = numberOfTree(n);
    cout<<ans;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值