二叉树相关题解java实现。
一、重建二叉树(剑6)
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
- 根据前序遍历的特点,我们知道根结点为1
- 观察中序遍历。其中root节点G左侧的472必然是root的左子树,G右侧的5386必然是root的右子树。
- 观察左子树472,左子树的中的根节点必然是大树的root的leftchild。在前序遍历中,大树的root的leftchild位于root之后,所以左子树的根节点为2。
- 同样的道理,root的右子树节点5386中的根节点也可以通过前序遍历求得。在前序遍历中,一定是先把root和root的所有左子树节点遍历完之后才会遍历右子树,并且遍历的左子树的第一个节点就是左子树的根节点。同理,遍历的右子树的第一个节点就是右子树的根节点。
- 观察发现,上面的过程是递归的。先找到当前树的根节点,然后划分为左子树,右子树,然后进入左子树重复上面的过程,然后进入右子树重复上面的过程。最后就可以还原一棵树了。
该步递归的过程可以简洁表达如下:
- 确定根,确定左子树,确定右子树。
- 在左子树中递归。
- 在右子树中递归。
- 打印当前根。
递归代码如下:
|
|
第二步是判断树A中以R为根结点的子树是不是和树B具有相同的结构。同样,我们也可以用递归的思路来考虑:如果结点R的值和树B的根结点不同,则以R为根结点的子树和树B一定不具有相同的结点;如果他们的值相同,则递归地判断它们各自的左右结点的值是不是相同。递归的终止条件是我们达到了树A或者树B的叶结点。
代码如下:
java
|
|
二叉树相关的代码有大量的指针操作,每一次使用指针的时候,我们都要问自己这个指针有没有可能是NULL,如果是NULL该怎么处理。
三、二叉树的镜像(剑19)
操作给定的二叉树,将其变换为源二叉树的镜像。
|
|
四、从上往下打印二叉树(剑23)
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
每次打印一个结点时,如果该结点有子结点,则把该结点的子结点放到队列的末尾。接下来到队列的头部取出最早进入队列的结点,重复前面的打印操作。
java
|
|
五、二叉搜索树的后序遍历序列(剑24)
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
在后序遍历得到的序列中,最后一个数字是树的根结点的值。数组中前面的数字可以分成两部分:第一部分是左子树结点的值,它们都比根结点小;第二部分是右子树结点的值,它们都比根结点大。
java
|
|
六、二叉树中和为某一值的路径(剑25)
输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
java
|
|
七、二叉搜索树与双向链表(剑27)
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
java
|
|
八、二叉树的深度(剑39.1)
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
Java 经典的求二叉树深度 递归写法
java
|
|
九、平衡二叉树(剑39.2)
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
有了求二叉树的深度的经验之后,我们就很容易想到一个思路:在遍历树的每个结点的时候,调用函数TreeDepth得到它的左右子树的深度。如果每个结点的左右子树的深度相差都不超过1,按照定义它就是一颗平衡的二叉树。
java
|
|
十、二叉搜索树的最低公共祖先(剑50.1)
二叉搜索树是经过排序的,位于左子树的节点都比父节点小,位于右子树的节点都比父节点大。既然要找最低的公共祖先节点,我们可以从根节点开始进行比较。若当前节点的值比两个节点的值都大,那么最低的祖先节点一定在当前节点的左子树中,则遍历当前节点的左子节点;反之,若当前节点的值比两个节点的值都小,那么最低的祖先节点一定在当前节点的右子树中,则遍历当前节点的右子节点;这样,直到找到一个节点,位于两个节点值的中间,则找到了最低的公共祖先节点。
java
|
|
十一、普通二叉树的最低公共祖先(剑50.2)
一种简单的方法是DFS分别寻找到两个节点p和q的路径,然后对比路径,查看他们的第一个分岔口,则为LCA。
这个思路比较简单,代码写起来不如下面这种方法优雅:
我们仍然可以用递归来解决,递归寻找两个带查询LCA的节点p和q,当找到后,返回给它们的父亲。如果某个节点的左右子树分别包括这两个节点,那么这个节点必然是所求的解,返回该节点。否则,返回左或者右子树(哪个包含p或者q的就返回哪个)。复杂度O(n)
java
|
|
十二、二叉树的下一个结点(剑58)
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
我们可发现分成两大类:
- 有右子树的,那么下个结点就是右子树最左边的点;(eg:D,B,E,A,F,C,G)
- 没有右子树的,也可以分成两类,a)是父节点左孩子(eg:N,I,L) ,那么父节点就是下一个节点 ; b)是父节点的右孩子(eg:H,J,K,M)找他的父节点的父节点的父节点…直到当前结点是其父节点的左孩子位置。如果没有eg:M,那么他就是尾节点。
java
|
|
十三、对称的二叉树(剑59)
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
如果先序遍历的顺序分为两种先左后右和先右后左两种顺序遍历,如果两者相等说明二叉树是对称的二叉树
java
|
|
十四、把二叉树打印成多行(剑60)
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
用end记录每层结点数目,start记录每层已经打印的数目,当start=end,重新建立list,开始下一层打印。
java
|
|
十五、按S型打印二叉树(剑61)
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
java
|
|
十六、序列化与反序列化二叉树(剑62)
请实现两个函数,分别用来序列化和反序列化二叉树
算法思想:根据前序遍历规则完成序列化与反序列化。所谓序列化指的是遍历二叉树为字符串;所谓反序列化指的是依据字符串重新构造成二叉树。
依据前序遍历序列来序列化二叉树,因为前序遍历序列是从根结点开始的。当在遍历二叉树时碰到Null指针时,这些Null指针被序列化为一个特殊的字符“#”。另外,结点之间的数值用逗号隔开。
java
|
|
十七、二叉搜索树的第K个结点(剑63)
给定一颗二叉搜索树,请找出其中的第k大的结点。例如在下图二叉搜索树里,按结点数值大小顺序第三个结点的值是4.
如果按照中序遍历的顺序遍历一颗二叉搜索树,遍历序列的数值是递增排序的,只需要用中序遍历算法遍历一颗二叉搜索树,就很容易找出它的第K大的结点。
java
|
|
十八、数据流中的中位数(剑64)
Java的PriorityQueue是从JDK1.5开始提供的新的数据结构接口,默认内部是自然排序,结果为小顶堆,也可以自定义排序器,比如下面反转比较,完成大顶堆。
为了保证插入新数据和取中位数的时间效率都高效,这里使用大顶堆+小顶堆的容器,并且满足:
- 两个堆中的数据数目差不能超过1,这样可以使中位数只会出现在两个堆的交接处;
- 大顶堆的所有数据都小于小顶堆,这样就满足了排序要求。
java
|
|
十九、 二叉树最大路径和(leetcode 124)
一个很有意思的问题,一个社区,所有的房子构成一棵二叉树,每个房子里有一定价值的财物,这棵二叉树有一个根节点root。如果相邻的两座房子同时被进入,就会触发警报。一个小偷,最初只能访问root节点,并可以通过二叉树的边访问房子(注:访问不意味着进入),请问不触发警报的前提下他能偷到的财物的最大价值是多少?
|
|
分析:
这个问题乍一看上去可能没什么思路,但是如果是用递归,可以很优雅的解决这个问题,这需要读者对递归有比较深刻的理解。下面给出解决这个问题的java代码:
|
|
面经中出现过的二叉树题:
已整理
- 一、给定二叉树的先序跟后序遍历,能不能将二叉树重建(不能,因为先序:父节点-左节点-右节点,后序:左节点-右节点-父节点,两者的拓扑序列是一样的,所以无法建立),如果给出一个二叉搜索树的后续能不能建立(可以,因为只要将遍历结果排序就可以得到中序结果)。
- 二、判断一棵树是否是另一棵的子树。
- 三、 翻转二叉树
- 四、二叉树打印路径
- 六、输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。二叉树路径和等于某个值的所有路径输出。
- 七、排序二叉树转双向链表
- 十、输入根节点和两个子节点,找到最小公共父节点,2叉树只有孩子节点;查找二叉树某两个节点的最近公共祖先
- 十二、输入二叉树节点 P, 找到二叉树中序遍历 P 的下一个节点。
- 十四、把二叉树打印成多行;中序遍历二叉树,利用O(1)空间统计遍历的每个节点的层次
- 十五、手写S型遍历二叉树,如何优化,最后说了个空间优化的方法
- 十九、leetcode 124 二叉树最大路径和
未整理
求完全二叉树的节点个数,要求最优解法,我写的是递归,复杂度O(logn*logn)