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)个结点时,可以构建多少种形态不同的树. 如果两棵树中各个结点的位置都一一对应,可以说这两棵树相似.如果两棵树不仅相似,而且对应结点上的数据也相同,就可以说这两 ...
随机推荐
- NOI 题库 8471 题解
8471 切割回文 描述 阿福最近对回文串产生了非常浓厚的兴趣. 如果一个字符串从左往右看和从右往左看完全相同的话,那么就认为这个串是一个回文串.例如,“abcaacba”是一个回文串,“abca ...
- java空指针异常:java.lang.NullPointException
一.什么是java空指针异常 我们都知道java是没有指针的,这里说的"java指针"指的就是java的引用,我们不在这里讨论叫指针究竟合不合适,而只是针对这个异常本身进行分析.空 ...
- Windows下ActiveMQ下载、安装部署
1.下载:http://activemq.apache.org/download.html 最新Windows版本 2.安装 (1) 首先配置JAVA环境变量 JAVA_HOME=D:\Progr ...
- STM32之PWM君
PWM..英语好的人估计又知道这三个大写字母代表哪三个英语单词了.小弟不才,就说中文意思好了:脉冲宽度调制,玩过飞思卡尔的人估计对PWM非常的不陌生吧.电机驱动需要PWM,控制舵机的转向需要PWM,总 ...
- RequireJS与SeaJS模块化加载示例
web应用越变的庞大,模块化越显得重要,尤其Nodejs的流行,Javascript不限用于浏览器,还用于后台或其他场景时,没有Class,没有 Package的Javascript语言变得难以管理, ...
- Java json串生成及转bean
package com; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import j ...
- html5 炫酷的字幕雨
<!DOCTYPE html> <html> <head> <script src="http://tj.gamee456.com/jquery.1 ...
- Mvc form提交
在项目开发中,我们离不开表单提交,本篇主要记录mvc的Ajax.BeginForm提交方式. 需要用到的js @Url.Script("~/Content/Scripts/jquer ...
- 基于AT89C51单片机的贪吃蛇电子游戏(仿真)
有关贪吃蛇的历史发展可以看一下这个网址,贪吃蛇最初的设计和现在并不相同..http://www.techweb.com.cn/internet/2013-02-21/1278055.shtml 该项目 ...
- HDFS Client 设计实现解析
前面对 HDFS NameNode 和 DataNode 的架构设计实现要点做了介绍,本文对 HDFS 最后一个主要构成组件 Client 做进一步解析. 流式读取 HDFS Client 为客户端应 ...