题目链接:

  不同的二叉查找树: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+;
long long ans = ;
for(int i=; i<=m; ++i){
ans *= n++;
ans /= i;
}
return ans;
}
int numTrees(int n) {
// write your code here
return C(*n, n)/(n+);
}
};

构建不同形态二叉树:

样例

  给出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=;//节点的总数
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== && rd==cntNode)
curRoot = T;
if(useNode+==cntNode){//这个树已经建立完毕,拷贝一下吧
TreeNode *tmp = NULL;
copyT(tmp, curRoot);
ans.push_back(tmp);
}
buildT(T->left, ld, root-, useNode+);
buildT(T->right, root+, rd, useNode+root-ld+);
}
}
vector<TreeNode *> generateTrees(int n) {
// write your code here
cntNode = n;
TreeNode *T = NULL;
buildT(T, , n, );
if(n == ) 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-);
vector<TreeNode *> ansRight = buildT(i+, 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 here
vector<TreeNode *> ans = buildT(, n);
return ans;
}
};

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

n个结点,不同形态的二叉树(数目+生成)的更多相关文章

  1. 【Leetcode】查找二叉树中任意结点的最近公共祖先(LCA问题)

    寻找最近公共祖先,示例如下: 1 /           \ 2           3 /    \        /    \ 4    5      6    7 /    \          ...

  2. 返回结点值为e的二叉树指针

    题意为,如果二叉树某结点的值为e(假定是整型二叉树),返回这个结点的指针.初看这道题,联想到二叉树可以很简单的遍历,直接返回这个指针不就行了吗?如下图所示,假如要返回值为3的结点指针: 设计好了一个函 ...

  3. 二叉树根结点到任意结点的路径(C语言)

    有一棵二叉树,如下图所示: 其中 # 表示空结点. 先序遍历:A B D E G C F 问题:怎么得到从根结点到任意结点的路径呢? 示例:输入 G,怎么得到从结点 A 到结点 G 的路径呢? 很明显 ...

  4. 剑指offer:JZ8 二叉树的下一个结点

    JZ8 二叉树的下一个结点 描述 给定一个二叉树其中的一个结点,请找出中序遍历顺序的下一个结点并且返回.注意,树中的结点不仅包含左右子结点,同时包含指向父结点的next指针.下图为一棵有9个节点的二叉 ...

  5. SOJ 1210 二叉树

    1210. 二叉树 Constraints Time Limit: 1 secs, Memory Limit: 32 MB Description 在众多的数据结构中,二叉树是一种特殊而重要的结构,有 ...

  6. 数据结构之二叉树(BinaryTree)

    导读 二叉树是一种很常见的数据结构,但要注意的是,二叉树并不是树的特殊情况,二叉树与树是两种不一样的数据结构. 目录 一. 二叉树的定义 二.二叉树为何不是特殊的树 三.二叉树的五种基本形态 四.二叉 ...

  7. Python数据结构——二叉树

    数的特征和定义: 树是一种重要的非线性数据结构,直观地看,它是数据元素(在树中称为结点)按分支关系组织起来的结构,很象自然界中的树那样.树结构在客观世界中广泛存在,如人类社会的族谱和各种社会组织机构都 ...

  8. 【C#数据结构系列】树和二叉树

    线性结构中的数据元素是一对一的关系,树形结构是一对多的非线性结构,非常类似于自然界中的树,数据元素之间既有分支关系,又有层次关系.树形结构在现实世界中广泛存在,如家族的家谱.一个单位的行政机构组织等都 ...

  9. 数据结构42:n个结点构造多少种树

    本节要讨论的是当给定 n(n>=0)个结点时,可以构建多少种形态不同的树. 如果两棵树中各个结点的位置都一一对应,可以说这两棵树相似.如果两棵树不仅相似,而且对应结点上的数据也相同,就可以说这两 ...

随机推荐

  1. PHP浮点数精度问题

    这一段时间维护一个类似团购的系统,需要处理订单,也就难免会处理金额 所以有很多PHP的坑 被我狠狠的踩了~~ 首先我们要知道浮点数的表示(IEEE 754): 简言之 就是 埋下了一个大坑 等着你跳 ...

  2. [BZOJ4200][Noi2015]小园丁与老司机

    4200: [Noi2015]小园丁与老司机 Time Limit: 20 Sec  Memory Limit: 512 MBSec  Special JudgeSubmit: 106  Solved ...

  3. Android 学习笔记之一 “Unable to establish loopback connection”

    今天碰到一个错误:Unable to establish loopback connection,在网上找各种方法都解决不了,后来看一个帖子说是要关闭系统防火墙,尝试了下还是不行.最后是进任务管理器杀 ...

  4. 【Redis】:Jedis 使用

    Redis 支持很多语言, 例如C#,RUBY,JAVA 等, Jedis是redis的java版本的客户端实现 一个简单的Jedis使用 依赖第三方包jedis-2.7.2.jar commons- ...

  5. spring3.0使用annotation完全代替XML(续)

    从回帖的反应来看,大多数人还是不赞成完全代替XML的,这点倒是在意料之中.我个人还是倾向于用代码来取代XML的Bean定义,当然这更多的是关乎个人偏好,不代表与我观点不同的人就是错的. 先来说说代码相 ...

  6. clear属性

    clear:规定元素的哪一侧不允许其他浮动元素. clear 属性定义了元素的哪边上不允许出现浮动元素.在 CSS1 和 CSS2 中,这是通过自动为清除元素(即设置了 clear 属性的元素)增加上 ...

  7. iOS 面试总结 二

    1.用三种方法生成内容为数字 1,2 ,3 的可变数组.(使用Objective-C,尽量一行代码实现) //方法一 NSMutableArray *arr1 = [[NSMutableArray a ...

  8. Web服务网站故障分析常用的命令

    1.查看TCP连接状态netstat -nat |awk ‘{print $6}’|sort|uniq -c|sort -rn netstat -n | awk ‘/^tcp/ {++S[$NF]}; ...

  9. 正则表达式preg_replace中危险的/e修饰符带来的安全漏洞问题

    mixed preg_replace ( mixed pattern, mixed replacement, mixed subject [, int limit]) /e 修饰符使 preg_rep ...

  10. Jquery学习插件之手风琴

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...