首页 > 试题广场 >

二叉树

[编程题]二叉树
  • 热度指数:4406 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 128M,其他语言256M
  • 算法知识视频讲解
小强现在有个节点,他想请你帮他计算出有多少种不同的二叉树满足节点个数为且树的高度不超过的方案.因为答案很大,所以答案需要模上1e9+7后输出.
树的高度: 定义为所有叶子到根路径上节点个数的最大值.
例如: 当n=3,m=3时,有如下5种方案:
数据范围:
进阶:时间复杂度,空间复杂度

输入描述:
第一行输入两个正整数.



输出描述:
输出一个答案表示方案数.
示例1

输入

3 3

输出

5
示例2

输入

3 2

输出

1
示例3

输入

4 3

输出

6
import java.util.*;

public class Main{
    public static final int MOD = 1000000007;

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int m = in.nextInt();
        // dp[i][j]表示i个节点最大深度为j的树数量
        long[][] dp = new long[n+1][m+1];
        Arrays.fill(dp[0], 1);
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                for(int k = 0; k < i; k++) {
                    // 左子树节点数为k,右子树节点数为i-k-1,且左右子树都要求小于等于j-1
                    dp[i][j] = (dp[i][j] + dp[k][j-1] * dp[i-k-1][j-1] % MOD) % MOD;
                }
            }
        }
        System.out.println(dp[n][m]);
    }
}
发表于 2021-07-04 17:33:37 回复(0)
#include <bits/stdc++.h>

using namespace std;

const int MOD = 1e9 + 7;

int main() {
    int n; // 节点个数
    int m; // 最大高度
    cin >> n >> m;
    
    // dp[i][j] 表示 i 个节点能够组成的高度不超过 j 的树的个数
    vector<vector<long long>> dp(n + 1, vector<long long>(m + 1));
    for(int i = 0; i <= m; ++i) {
        dp[0][i] = 1;
    }
    
    for(int i = 1; i <= n; ++i) {
        for(int j = 1; j <= m; ++j) {
            // 选取一个节点作为根节点
            // k 个节点作为左子树,i - k - 1 个节点作为右子树
            for(int k = 0; k < i; ++k) {
                dp[i][j] = (dp[i][j] + dp[k][j - 1] * dp[i - k - 1][j - 1] % MOD) % MOD;
            }
        }
    }
    
    cout << dp[n][m] << endl;
}

发表于 2021-08-11 16:53:27 回复(2)
N个结点二叉树的个数是卡特兰数,计算方法可以用递归思想得到,此题目同样如此,但还要增加一个高度限制。因此用二维数组来做dp。
N个点,高度不大于M二叉树,可以由二分为两棵子树,高度不大于M-1,此时注意子树节点数量不能超过2^(M-1)-1。
介绍下另一个衍生问题?N个点,高度恰好等于M的二叉树有多少种。
高度恰好等于M的二叉树=不超过M的二叉树总数-不超过M-1的二叉树总数
#include <bits/stdc++.h>//ASI
typedef long long ll;
using namespace std;
ll n,m,mod=1000000007,f[55][55];
ll dfs(ll n,ll m)
{
    if(n<=1)
        return 1;
    if(f[n][m])
        return f[n][m];
    ll ans=0,i;
    for(i=0; i<n; i++)
    { /**< 易错点,1<<(m-1)当m大于33时会出错。 */
        if(i<=(1LL<<(m-1))-1&&n-1-i<=(1LL<<(m-1))-1)
            ans=(ans+dfs(i,m-1)*dfs(n-1-i,m-1)%mod)%mod;
    }
    return f[n][m]=ans;
}
int main()
{
    int i,j;
    cin>>n>>m;
    cout<<dfs(n,m)<<endl;
    return 0;
}


编辑于 2022-09-11 22:36:20 回复(0)
#include<bits/stdc++.h>
using namespace std;
const int ll = 1000000007;

int main(){
    int n, m;
    cin >> n >> m;
    //dp[i][j]:i个节点且高度不超过j的二叉树个数
    vector<vector<long>> dp(n + 1, vector<long>(m + 1, 0));
    //初始化dp[0][j] = 1, 即不同高度的空树都只有一种可能
    for(int j = 0; j <= m; j++){
        dp[0][j] = 1;
    }
    //其他dp[i][0]都为0
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            //k为左子树节点数,总共有i个节点, 故右子树有i - 1 - k个节点, i ~[0, i - 1]
            for(int k = 0; k < i; k++){
                //乘法原理,左右子树两两组合,左右子树高度减1
                dp[i][j] = (dp[i][j] + dp[k][j - 1] * dp[i - 1 - k][j - 1]) % ll;
            }
        }
    }
    cout << dp[n][m] << endl;
}
发表于 2022-03-13 19:50:34 回复(0)
#区间dp
n,m=map(int,input().split(' '))
row=n+1
col=m+1
mod=10**9+7
#dp[n][m]值代表节点为n,层数不超过m的树的大小
dp=[[0 for _ in range(m+1)]for _ in range(n+1)]
#初始化
for j in range(1,col):
    dp[0][j]=1
    dp[1][j]=1
for i in range(2,row):
    for j in range(2,col):
        for k in range(0,i):
            #print([i,j],[k,j-1],[i-1-k,j-1])
            #举例:dp[3][3]=dp[0][2]*dp[2][2]+dp[1][2]*dp[1][2]+dp[2][2]*dp[0][2]
            #左右子树用乘法原理,不同组合用加法原理
            dp[i][j]+=dp[k][j-1]*dp[i-1-k][j-1]
            dp[i][j]=dp[i][j]%mod
#print(dp)
print(dp[n][m])
发表于 2021-08-31 11:28:37 回复(0)
始终有两个过不了,麻烦大佬给看看是怎么回事T_T
n, h = list(map(int, input().split()))
MAXN = 1e9 + 7
visited = [[0]*55 for i in range(55)]
def getNumOfTrees(n, h):
    if h == 1:
        return 1 if n < 2 else 0
    if n < 2:
        return 1
    if visited[n][h] != 0:
        return visited[n][h]
    ret = 0
    for i in range(n):
        l = getNumOfTrees(i, h-1) if i < pow(2, h-1) else 0
        r = getNumOfTrees(n-1-i, h-1) if (n-1-i) < pow(2, h-1) else 0
        ret += l * r
        ret %= MAXN
    visited[n][h] = ret
    return int(ret % MAXN)
print(getNumOfTrees(n, h))


编辑于 2021-09-14 14:07:27 回复(1)
方法就是计算左子树和右子树中高度满足要求的有多少种,最后加起来
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        int b = sc.nextInt();
        System.out.println(f(a, b));
    }

    public static int f(int a, int b) {
        int mod =  1000000007;
        //dp[i][j]表示节点数为i,高度不高于j的树的数量
        long [][] dp = new long[a + 1][b + 1];
        //首先,节点数为0的树,高度可以任意
        for (int i = 0; i <= b; i++) {
            dp[0][i] = 1;
        }
        //其次,除了节点数也为0的,高度为0的树是不存在的
        for (int i = 1; i <= a; i++) {
            dp[i][0] = 0;
        }
        for (int i = 1; i <= a; i++) {
            for (int j = 1; j <= b; j++) {
                //对于含有i个节点,高度不高于j的树,有如下判断
                //除去根节点,左右子树加起来共有i-1个节点
                for (int k = 0; k <= i - 1; k++) {
                    if(j>i){
                        dp[i][j] = dp[i][i];
                    }else{
                        //左子树节点数为k,而且高度不高于j-1的
                        long left = k==0?1:dp[k][j-1];
                        //右子树节点数为i-1-k,而且高度不高于j-1的
                        long right = i-1-k==0?1:dp[i-1-k][j-1];
                        dp[i][j] += left*right%mod;
                        dp[i][j] %= mod;
                    }
                }
            }
        }
        return (int)dp[a][b];
    }

}


发表于 2021-09-06 21:35:57 回复(0)
#include <iostream>
using namespace std;
#include<vector>
typedef long long ll;
const int mod = 1e9 + 7;
//节点数为n高度不超过m的不同二叉树结构数量
int helper(int n,int m,vector<vector<ll>>& dp){
    if(n == 0) return 1;
    if(m == 0) return 0;
    if(dp[n][m] != -1) return dp[n][m];
    ll ans = 0;
    for(int k = 0;k < n;k ++){
        ans = (ans + (ll)helper(n - 1 - k,m - 1,dp) * helper(k,m - 1,dp) % mod) % mod;
    }
    return dp[n][m] = ans;

}
int main() {
    int n,m;
    cin >> n >> m;
    vector<vector<ll>> dp(n + 1,vector<ll>(m + 1,-1));
    cout << helper(n,m,dp) << endl;
    return 0;
 
}
发表于 2024-03-24 13:45:51 回复(0)
import sys
from functools import cache
from math import log2


@cache
def dfs(n: int, m: int) -> int:
    if n == 0:
        return 1
    if m < int(log2(n)) + 1:
        return 0
    acc = 0
    for k in range(n):
        acc += dfs(k, m - 1) * dfs(n - 1 - k, m - 1)
    return acc % e


n, m = map(int, input().split())
e = 10 ** 9 + 7
print(dfs(n, m))
python,记忆化搜索版本
发表于 2023-08-11 10:10:39 回复(0)
import java.util.*;
import java.io.*;
public class Main {
    private static long[][] dp;
    private static  int m;
    private static  long mod = (long)1e9 + 7;
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String s = null;
        while ((s = reader.readLine()) != null) {
            String[] s1 = s.split(" ");
            int n = Integer.parseInt(s1[0]);
            m = Integer.parseInt(s1[1]);

            dp = new long[n + 1][m + 1];
            for (int i = 0; i <= n; i++) {
                Arrays.fill(dp[i], -1);
            }
            long res = highestNum(n,0);
            System.out.println(res);
        }

    }

    //左右节点数量,高度作为状态
    public static long highestNum(int treeNum, int high) {
        if (high > m) {
            return 0l;
        }
        if (treeNum == 0) {
            return 1l;
        }

        if (dp[treeNum][high] != -1l) {
            return dp[treeNum][high];
        }
        long ans = 0l;
        treeNum--;
        for (int i = 0; i <= treeNum; i++) {

            long left = highestNum(i, high + 1);
            long right = highestNum(treeNum - i, high + 1);
            ans = (ans +((left % mod) * (right % mod))) % mod;
        }
        treeNum++;
        dp[treeNum][high] = ans;
        return ans;

    }
}

发表于 2022-10-17 12:30:11 回复(0)
import numpy as np
n=int(input())
m=int(input())
MOD=1e9+7 data=np.zeros([n+1,m+1],int)
data[0]=[1]*(m+1) for i in range(1,n+1): for j in range(1,m+1): for k in range(i):
            data[i][j]=(data[i][j]+data[k][j-1]*data[i-k-1][j-1] % MOD)%MOD print(data[i][j])

编辑于 2022-03-03 14:36:51 回复(0)
注意:
1. 因为答案很大,所以答案需要模上1e9+7后输出.
              int aa = (dp[k][j-1] * dp[i-k-1][j-1])% mod;
                 dp[i][j] += aa;
                 dp[i][j] %= mod;


编辑于 2021-10-27 20:50:07 回复(0)
#include <bits/stdc++.h>
using namespace std;
#define MOD (int)(1e9+7)

int main()
{
    int n,m;
    cin>>n>>m;
    vector<vector<long long>> dp(n+1,vector<long long>(m+1,0));
    for(int i=1;i<=m;++i)
    {
        int limit=i<7?((1<<i)-1):INT_MAX;
        for(int j=0;j<=n;++j)
        {
            if(j>limit) dp[j][i]=0;
            else if(j==limit||j==0) dp[j][i]=1;
            else
            {
                if(i==1||j==1) dp[j][i]=1;
                else
                {
                    for(int x=0;x<j;++x)
                        dp[j][i]=(dp[j][i]+dp[x][i-1]*dp[j-1-x][i-1])%MOD;
                }
            }
        }
    }
    cout<<dp[n][m]%MOD;
    return 0;
}
发表于 2021-08-26 20:44:22 回复(0)
#include <iostream>
#include <vector>
using namespace std;
const int MOD = 1e9 + 7;

//n个节点,高度不超过m一共能组成多少棵BST
long long numofBST(int n, int m){
    vector<vector<long long> > dp(n+1, vector<long long>(m+1));
    for(int j = 0; j <= m; j++){
        dp[0][j] = 1;
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            for(int k = 0; k < i; k++){ //先用一个点构成root,左子树有k个,右子树有i-k-1个
                dp[i][j] = (dp[i][j] + dp[k][j-1] * dp[i-k-1][j-1] % MOD) % MOD;
            }
        }
    }
    return dp[n][m];
}

int main(){
    int n, m;
    cin >> n >> m;
    cout << numofBST(n, m);
    return 0;
}

发表于 2021-08-26 15:49:08 回复(0)
#include<bits/stdc++.h>
using namespace std;
static const int mod = 1e9+7;
int main(){
    int n,m;
    while(cin>>n>>m){
        vector<vector<long>> dp(n+1,vector<long>(m+1));
        for(int i=0;i<=m;i++) dp[0][i] = 1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                for(int k=0;k<=i-1;k++)
                    dp[i][j] = (dp[i][j] + dp[i-1-k][j-1]*dp[k][j-1]%mod)%mod;
        cout<<dp[n][m]<<endl;
    }
}

发表于 2021-07-30 22:52:21 回复(0)
# i->节点数 j->二叉树的高度
# 卡特兰数列,状态转移方程应限制树的高度
# dp[i][j] = dp[i-(i-1)-1][j-1]*dp[(i-1)]dp[j-1] + ...
n, m = input().split()
n, m = int(n), int(m)
dp = [[0]*(m+1) for i in range(n+1)]
# 初始状态:结点数为零,只有一种方案
for j in range(m+1):
    dp[0][j] = 1
for i in range(1, n+1):
    for j in range(1, m+1):
        for re in range(i):
            # re + (i-re-1) = i-1
            dp[i][j] += dp[re][j-1]*dp[i-re-1][j-1]
print(dp[-1][-1]%(10**9+7))


发表于 2021-07-25 22:19:17 回复(1)

热门推荐

通过挑战的用户

查看代码