题目链接:

  不同的二叉查找树:http://www.lintcode.com/zh-cn/problem/unique-binary-search-trees/

  不同的二叉查找树 II:http://www.lintcode.com/zh-cn/problem/unique-binary-search-trees-ii/

不同形态二叉树的数目:

样例

  给出n = 3,有5种不同形态的二叉查找树:

  1           3    3       2      1\         /    /       / \      \3      2     1       1   3      2/      /       \                  \2     1          2                  3

分析

   可以分析,当n=1时,只有1个根节点,则只能组成1种形态的二叉树,令n个节点可组成的二叉树数量表示为h(n),则h(1)=1; h(0)=0;

当n=2时,1个根节点固定,还有2-1个节点。这一个节点可以分成(1,0),(0,1)两组。即左边放1个,右边放0个;或者左边放0个,右边放1个。即:h(2)=h(0)*h(1)+h(1)*h(0)=2,则能组成2种形态的二叉树。

当n=3时,1个根节点固定,还有2个节点。这2个节点可以分成(2,0),(1,1),(0,2)3组。即h(3)=h(0)*h(2)+h(1)*h(1)+h(2)*h(0)=5,则能组成5种形态的二叉树。

以此类推,当n>=2时,可组成的二叉树数量为h(n)=h(0)*h(n-1)+h(1)*h(n-2)+...+h(n-1)*h(0)种,即符合Catalan数的定义,可直接利用通项公式得出结果。

令h(1)=1,h(0)=1,catalan数(卡特兰数)满足递归式:

  h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (其中n>=2)

  另类递归式:

h(n)=((4*n-2)/(n+1))*h(n-1);

  该递推关系的解为:

  h(n)=C(2n,n)/(n+1) (n=1,2,3,...)

  由此想到了上次说的"N个数依次入栈,出栈顺序有多少种?",  同样用的也是卡特兰数。

   http://www.cnblogs.com/hujunzheng/p/4845354.html

代码

class Solution {
public:/*** @paramn n: An integer* @return: An integer*/long long C(int n, int m){n = n-m+1;long long ans = 1;for(int i=1; i<=m; ++i){ans *= n++;ans /= i;}return ans;}int numTrees(int n) {// write your code herereturn C(2*n, n)/(n+1);}
};

构建不同形态二叉树:

样例

  给出n = 3,生成所有5种不同形态的二叉查找树:

  1         3     3       2    1\       /     /       / \    \3     2     1       1   3    2/     /       \                \2     1         2                3

  其实通过样例,我们可以发现n个结点构造不同形态二叉树的过程,1,2,3.....n个结点,枚举每一个结点为根结点(假设为root, 1<=root<=n), 那么(1,2..root-1)和(root+1, root+2...n)分别是root的左右子树。每一步不断地重复上述过程,最终会得到所有形态的二叉树。

算法实现

  先弱弱的说一下自己错误的实现,因为递归实现的时候会得到不同的二叉树,那么如何判断n个结点正好生成了二叉树呢?于是用了一个变量useNode(=0),表示当前已经用了多少个结点建树。当useNode等于n的时候说明产生了一棵符合要求的树,接着拷贝一下刚才生成的树,然后放入vector中,继续建造下一棵符合条件的二叉树。

错误代码:

/*** Definition of TreeNode:* class TreeNode {* public:*     int val;*     TreeNode *left, *right;*     TreeNode(int val) {*         this->val = val;*         this->left = this->right = NULL;*     }* }*/
class Solution {
public:/*** @paramn n: An integer* @return: A list of root*/vector<TreeNode *> ans;int cntNode=0;//节点的总数TreeNode *curRoot = NULL;void copyT(TreeNode * &tmp, TreeNode *T){if(T){tmp = new TreeNode(T->val);copyT(tmp->left, T->left);copyT(tmp->right, T->right);}}void buildT(TreeNode * &T, int ld, int rd, int useNode){if(ld > rd) return;for(int root=ld; root<=rd; ++root){T = new TreeNode(root);if(ld==1 && rd==cntNode)curRoot = T;if(useNode+1==cntNode){//这个树已经建立完毕,拷贝一下吧TreeNode *tmp = NULL;copyT(tmp, curRoot);ans.push_back(tmp);}buildT(T->left, ld, root-1, useNode+1);buildT(T->right, root+1, rd, useNode+root-ld+1);}}vector<TreeNode *> generateTrees(int n) {// write your code herecntNode = n;TreeNode *T = NULL;buildT(T, 1, n, 0);if(n == 0) ans.push_back(T);return ans;}
};

  后来运行之后,看到错误的答案与正确答案的对比,如下:

  当n=4的时候

  输出

[{1,#,2,#,3,#,4},{1,#,2,#,4,3},{1,#,3,2,4},{1,#,4,2,#,#,3},{1,#,4,3,#,2},{2,1,3,#,#,#,4},{2,1,4,#,#,3},{3,2,4,1},{4,1,#,#,2,#,3},{4,1,#,#,3,2},{4,2,#,1,3},{4,3,#,1,#,#,2},{4,3,#,2,#,1}]

  期望答案

[{1,#,2,#,3,#,4},{1,#,2,#,4,3},{1,#,3,2,4},{1,#,4,2,#,#,3},{1,#,4,3,#,2},{2,1,3,#,#,#,4},{2,1,4,#,#,3},{3,1,4,#,2},{3,2,4,1},{4,1,#,#,2,#,3},{4,1,#,#,3,2},{4,2,#,1,3},{4,3,#,1,#,#,2},{4,3,#,2,#,1}]

  也就是少了{3,1,4,#,2},以3为根结点的二叉树为什么会少了呢?仔细想想,3结点的左孩子可以是1,也可以是2,那么左孩子为1的情况就被忽略了,此时useNode并不等于n,然后就换成左孩子为2结点的情况了。

正确代码:

/*** Definition of TreeNode:* class TreeNode {* public:*     int val;*     TreeNode *left, *right;*     TreeNode(int val) {*         this->val = val;*         this->left = this->right = NULL;*     }* }*/
class Solution {
public:/*** @paramn n: An integer* @return: A list of root*/vector<TreeNode *> buildT(int ld, int rd){vector<TreeNode *> ans;if(ld == rd) {TreeNode *T = new TreeNode(ld);ans.push_back(T);return ans;}if(ld > rd){ans.push_back(NULL);return ans;}for(int i=ld; i<=rd; ++i){vector<TreeNode *> ansLeft = buildT(ld, i-1);vector<TreeNode *> ansRight = buildT(i+1, rd);for(auto lx : ansLeft)for(auto rx : ansRight){TreeNode *T = new TreeNode(i);T->left = lx;T->right = rx;ans.push_back(T);}}return ans;}vector<TreeNode *> generateTrees(int n) {// write your code herevector<TreeNode *> ans = buildT(1, n);return ans;}
};

  分析:在确定当前结点X后,那么X的左孩子结点(或右孩子结点)可能会有多个,那么就把这些可能的结点都存到vector中,然后从左孩子集合中任选出lx结点,以及从右孩子集合中选出rx结点,那么lx和rx就确定了一种形态的二叉树。

转载于:https://www.cnblogs.com/hujunzheng/p/5040334.html

n个结点,不同形态的二叉树(数目+生成)相关推荐

  1. 卡塔兰数用于求解不同形态的二叉树的数目,题目选自CS61A2021 LAB9 Q3: Number of Trees

    完全二叉树是一种每个节点都有2个分支或0个分支,但从来没有1个分支的树. 编写一个函数,返回恰好有n个叶结点的唯一完整二叉树结构的数目. 对于那些对组合学感兴趣的人来说,这个问题确实有一个封闭形式的解 ...

  2. 数据结构--二叉树--路径 假设二叉树采用二叉链表方式存储, root指向根结点,node 指向二叉树中的一个结点, 编写函数 path,计算root到 node 之间的路径,(该路径包括root结

    假设二叉树采用二叉链表方式存储, root指向根结点,node 指向二叉树中的一个结点, 编写函数 path,计算root到 node 之间的路径,(该路径包括root结点和 node 结点).pat ...

  3. [leetcode] 96. 不同的二叉搜索树 +[补充] 不同的二叉树,不同形态的二叉树的个数----catalan数

    leetcode官方的题解:https://leetcode-cn.com/problems/unique-binary-search-trees/solution/bu-tong-de-er-cha ...

  4. 设某种二叉树有如下特点:每个结点要么是叶子结点,要么有2棵子树。假如一棵这样的二叉树中有m(m0)个叶子结点,那么该二叉树上的结点总数为( )。

    设某种二叉树有如下特点:每个结点要么是叶子结点,要么有2棵子树.假如一棵这样的二叉树中有m(m>0)个叶子结点,那么该二叉树上的结点总数为( ). 正确答案: B   你的答案: B (正确) ...

  5. 7-4 (小字辈) 7-5 (列出叶结点) 7-6 (顺序存储的二叉树的最近的公共祖先问题)

    目录 7-4 小字辈 7-5 列出叶结点 7-6 顺序存储的二叉树的最近的公共祖先问题 总结: 7-4 小字辈 原题链接:题目详情 - 7-4 小字辈 (pintia.cn) 思路: 利用一维数组下标 ...

  6. 二叉树查找结点c语言_二叉树操作详解

    (给C语言与CPP编程加星标,提升C/C++技能) 来源:https://segmentfault.com/a/1190000008850005 [导读]:树是数据结构中的重中之重,尤其以各类二叉树为 ...

  7. 二叉树的进阶操作---(求二叉树中所有结点个数,求叶子结点个数,求第k层结点个数;在二叉树中查找某一结点;层序遍历;判断是否为完全二叉树)

    typedef struct TreeNode {struct TreeNode *left;struct TreeNode *right;char val; }TreeNode;typedef st ...

  8. c语言 怎么输出结点,c语言 线索二叉树 输入结点 输出前驱后继,大神们救命啊!!1...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 #include #include //定义结构体 typedef struct BiThrNode { int data; struct BiThrNo ...

  9. 设一棵完全二叉树共有500个结点,则在该二叉树中有______个叶子结点

    2^9 - 1 = 511 511 - 500 = 11 2 ^ 8 - 1 = 255 511 - 255 = 256 "所以缺少了11个右结点"的"右"字上 ...

最新文章

  1. Shell编程之matrix---装逼又炫酷
  2. python安装教程windows-PyCharm 安装教程(Windows)
  3. 做好信息安全 必须打造良好的企业安全文化
  4. C++ cin.putback()输入【已知行数】但【未知每行数字个数】的思路
  5. CentOS6.5安装MySQL5.7详细教程
  6. 【MaxCompute学习】隐式转化的问题
  7. 常用JavaScript函数 47 - 58(自我总结)
  8. 大数据之-Hadoop本地模式_执行Grep官方案例---大数据之hadoop工作笔记0021
  9. error 1044 (42000):access denied for user ''@'localhost' to database 'mysql'
  10. 笔记32 SpringMVC中使用静态资源、处理中文乱码
  11. 怎样快速修改论文格式-使用人工智能技术助手
  12. 用认知和人性来做最棒的程序员
  13. How browsers work----Introduction
  14. Docker —— 从入门到实践
  15. 广州微创软件科技有限公司面试总结
  16. Redis 之 SessionCallback RedisCallback 使用
  17. 真正的程序员到底应该是什么样子的?
  18. win10(家庭版)打开本地组策略失败的处理方法
  19. 【数据挖掘】2022数据挖掘之Matplotlib完整使用(折线图、散点图、柱状图、直方图、饼图)
  20. buuctf:Ping Ping Ping(命令执行)

热门文章

  1. axios链接带参数_axios常见传参方式
  2. 数据结构python吕云翔_《数据结构》吕云翔编著第1章绪论习题解答
  3. 2个 string 日期比较
  4. java.lang.NoClassDefFoundError: org/springframework/core/ErrorCoded
  5. JavaScript 常用工具函数
  6. Vue3 --- 安装和使用echarts
  7. php 模数 指数 公钥生成_php实现JWT认证
  8. 相对熵与交叉熵_详解机器学习中的熵、条件熵、相对熵、交叉熵
  9. java管理员登录_idea实现管理员登录javaweb
  10. C语言 函数不定长参数 - C语言零基础入门教程