不同的二叉搜索树 I、II

这篇博客探讨了两种不同的二叉搜索树问题。第一部分介绍了如何计算给定整数n所能形成的二叉搜索树的总数,利用卡特兰数的递推公式和动态规划方法。第二部分详细讲解了如何生成所有1到n节点的二叉搜索树,通过递归和序列分治策略避免重复计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

不同的二叉搜索树 I

题目描述

给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?
在这里插入图片描述
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-binary-search-trees
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

一、卡特兰数
长度为n的序列不同二叉搜索树的个数称为卡特兰数。卡特兰数更便于计算的定义如下:(避免阶乘运算( C ( n ) = 1 n + 1 C 2 n n C(n)=\dfrac{1}{n+1}C_{2n}^n C(n)=n+11C2nn))
C 0 = 1 C_0=1 C0=1, C n + 1 = 2 ( 2 n + 1 ) n + 2 C n C_{n+1}=\dfrac{2(2n+1)}{n+2}C_n Cn+1=n+22(2n+1)Cn
根据此递推公式,有如下代码

代码(c++)

class Solution {
public:
    int numTrees(int n) {
        long long temp=1;
        for(int i=0;i<n;i++){
            temp=temp*2*(2*i+1)/(i+2);
        }
        return int(temp);
    }
};

二、动态规划
求有序序列1…n构成不同二叉搜索树的总数,就是以序列中每个元素为根结点,左右两个子序列为左右子树构成的不同二叉搜索树的总数。子序列又重复这一过程。
定义两个函数:
G ( n ) G(n) G(n):长度为n的序列不同二叉搜索树的个数
F ( i , n ) F(i,n) F(i,n):以i为根结点的不同二叉搜索树个数
长度为n的序列不同二叉搜索树的总数是以其中每个元素为根得到的不同二叉搜索树的总数,所以有
G ( n ) = ∑ i = 1 n F ( i , n )            ( 1 ) G(n)=\sum\limits_{i=1}^{n}F(i,n) ~~~~~~~~~~(1) G(n)=i=1nF(i,n)          (1)
对于边界情况,当序列长度为 1 (只有根)或为 0 (空树)时,只有一种情况。亦即:
G ( 0 ) = 1 , G ( 1 ) = 1 G(0)=1, G(1)=1 G(0)=1,G(1)=1
以i为根结点的不同二叉搜索树个数 F ( i , n ) F(i,n) F(i,n)是左右子树个数的笛卡尔积,即两个子序列组合总数等于两个子序列长度的乘积,如下图所示:
在这里插入图片描述
于是有 F ( i , n ) = G ( i − 1 ) ⋅ G ( n − i )            ( 2 ) F(i,n)=G(i-1)\cdotp G(n-i)~~~~~~~~~~(2) F(i,n)=G(i1)G(ni)          (2)
结合(1)(2)可得递推式子:
G ( n ) = ∑ i = 1 n G ( i − 1 ) ⋅ G ( n − i )            ( 3 ) G(n)=\sum\limits_{i=1}^{n}G(i-1)\cdotp G(n-i) ~~~~~~~~~~(3) G(n)=i=1nG(i1)G(ni)          (3)

代码(c++)

class Solution {
public:
    int numTrees(int n) {
        vector<int> G(n+1,0);
        G[0]=1;
        G[1]=1;
        for(int i=2;i<=n;i++){
            for(int j=1;j<=i;j++){
                G[i]+=G[j-1]*G[i-j];
            }
        }
        return G[n];
    }
};

不同的二叉搜索树 II

题目描述

给定一个整数 n,生成所有由 1 … n 为节点所组成的二叉搜索树。
在这里插入图片描述
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-binary-search-trees-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

递归查找:
以当前序列中的每一个元素为根结点,将序列分成左右两个子序列,分别是当前根结点的左右子树序列,以同样的方法递归的搜索每个子序列中所有不同的二叉搜索树,最后递归返回到该层,将左右两个子序列中的所有二叉搜索树组合构成当前根结点的左右子树,并保存在当前递归层存储不同二叉树的容器中,以作为上一层根结点的左或右子树。
可以用一个map记录出现过的子树序列,避免重复查找。以序列左右端点构成的pair作为键,序列作为值。

代码(c++)

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<TreeNode*> find_search(map<pair<int,int>,vector<TreeNode*> > &mp,int left,int right){
        vector<TreeNode*> layer;
        if(left>right){
            layer.push_back(NULL);
            return layer;
        }
        if(left==right){
            TreeNode* temp=new TreeNode(left);
            layer.push_back(temp);
            return layer;
        }
        if(mp.find(make_pair(left,right))!=mp.end()) return mp[make_pair(left,right)];
        for(int i=left;i<=right;i++){
            vector<TreeNode*> l=find_search(mp,left,i-1);
            vector<TreeNode*> r=find_search(mp,i+1,right);
            for(int j=0;j<l.size();j++){
                for(int k=0;k<r.size();k++){
                    TreeNode* temp=new TreeNode(i);
                    temp->left=l[j];
                    temp->right=r[k];
                    layer.push_back(temp);
                }
            }
            mp[make_pair(left,right)]=layer;
        }
        return layer;
    }
    vector<TreeNode*> generateTrees(int n) {
        vector<TreeNode*> res;
        if(n==0) return res;
        map<pair<int,int>,vector<TreeNode*> > mp;
        int left=1,right=n;
        res=find_search(mp,left,right);
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值