n个结点,不同形态的二叉树(数目+生成)
题目链接:
不同的二叉查找树: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)=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个结点,不同形态的二叉树(数目+生成)的更多相关文章
- 【Leetcode】查找二叉树中任意结点的最近公共祖先(LCA问题)
寻找最近公共祖先,示例如下: 1 / \ 2 3 / \ / \ 4 5 6 7 / \ ...
- 返回结点值为e的二叉树指针
题意为,如果二叉树某结点的值为e(假定是整型二叉树),返回这个结点的指针.初看这道题,联想到二叉树可以很简单的遍历,直接返回这个指针不就行了吗?如下图所示,假如要返回值为3的结点指针: 设计好了一个函 ...
- 二叉树根结点到任意结点的路径(C语言)
有一棵二叉树,如下图所示: 其中 # 表示空结点. 先序遍历:A B D E G C F 问题:怎么得到从根结点到任意结点的路径呢? 示例:输入 G,怎么得到从结点 A 到结点 G 的路径呢? 很明显 ...
- 剑指offer:JZ8 二叉树的下一个结点
JZ8 二叉树的下一个结点 描述 给定一个二叉树其中的一个结点,请找出中序遍历顺序的下一个结点并且返回.注意,树中的结点不仅包含左右子结点,同时包含指向父结点的next指针.下图为一棵有9个节点的二叉 ...
- SOJ 1210 二叉树
1210. 二叉树 Constraints Time Limit: 1 secs, Memory Limit: 32 MB Description 在众多的数据结构中,二叉树是一种特殊而重要的结构,有 ...
- 数据结构之二叉树(BinaryTree)
导读 二叉树是一种很常见的数据结构,但要注意的是,二叉树并不是树的特殊情况,二叉树与树是两种不一样的数据结构. 目录 一. 二叉树的定义 二.二叉树为何不是特殊的树 三.二叉树的五种基本形态 四.二叉 ...
- Python数据结构——二叉树
数的特征和定义: 树是一种重要的非线性数据结构,直观地看,它是数据元素(在树中称为结点)按分支关系组织起来的结构,很象自然界中的树那样.树结构在客观世界中广泛存在,如人类社会的族谱和各种社会组织机构都 ...
- 【C#数据结构系列】树和二叉树
线性结构中的数据元素是一对一的关系,树形结构是一对多的非线性结构,非常类似于自然界中的树,数据元素之间既有分支关系,又有层次关系.树形结构在现实世界中广泛存在,如家族的家谱.一个单位的行政机构组织等都 ...
- 数据结构42:n个结点构造多少种树
本节要讨论的是当给定 n(n>=0)个结点时,可以构建多少种形态不同的树. 如果两棵树中各个结点的位置都一一对应,可以说这两棵树相似.如果两棵树不仅相似,而且对应结点上的数据也相同,就可以说这两 ...
随机推荐
- FileReader获取文件的base64编码
<input type="file" id="picFile" /> function readFile() { var obj = documen ...
- CentOS 7 学习笔记(一)时间管理
1 获取当前时间 [root@limt01 ~]# date 2015年 05月 22日 星期五 01:30:50 CST 2 获取当前日期 [root@limt01 ~]# date "+ ...
- Ambari组件黄色预警
Ambari组件黄色预警 组件上为黄色问号,代表心跳丢失,解决如下: 1. 查看个节点之间是否可以相互通信,若ssh连接不上,有可能是该节点关机了,没有打开,手动开启该节点,再次验证是否可互通. 2 ...
- 【Telerik】<telerik:RadComboBox>导出列表数据
近来在做项目,做到导出功能.使用<telerik:RadComboBox>的下拉框来实现导出部分或导出所有数据的功能.
- 使用mybatis-generator生成代码
文档地址: http://mbg.cndocs.tk/index.html 以下是一个简单的配置内容. 一.在maven配置文件中添加mybatis-generator插件 1 2 3 4 5 ...
- 初次接触nodejs,请多指教。
一 安装nodejs 1.下载node.js.在http://nodejs.org/download/下载最新版的node.exe文件,我下载时是v0.10.33.下载完成后,在F盘新建nodejs ...
- css3新属性object-fit,对页面img处理
1.http://my.xueh5.com/xh5639998239/detail-3661.html 针对其进行深度讲解推荐 http://www.zhangxinxu.com/wordpress/ ...
- 解决:View调用invalidate()后不刷新onDraw()
近来学android图片处理,按照例子来,自定义一个View,之后在Activity里面手动调用该View的invalidate()后,一直无法刷新onDraw() 上网搜了一下,有两种解决办法: 一 ...
- F.I.S初探(前端工程化)
云笔记:http://note.youdao.com/share/?id=7c4a2dcf118f0ad7bb52a36aaee46a7a&type=note 一.初识FIS 在做项目中遇 ...
- 剑指Offer面试题:3.替换空格
一.题目:替换空格 题目:请实现一个函数,把字符串中的每个空格替换成"%20".例如输入“We are happy.”,则输出“We%20are%20happy.”. 在网络编程中 ...