目录
案例一:用递归方式和非递归式实现二叉树的先序、中序和后序的遍历打印。
二叉树类型的题目为常考题型
1.能够结合队列,栈,链表,字符串等数据结构。
案例一:用递归方式和非递归式实现二叉树的先序、中序和后序的遍历打印。
先序遍历:
中序遍历:
后序遍历:
案例二:给定二叉树的头结点head,要求按照以下格式打印
案例三:二叉树的序列化与反序列化
案例四:判断一棵树是否为平衡二叉树
public boolean isBalance(Node head) {
boolean[] res = new boolean[1];
res[0] = true;
getHeight(head, 1, res);
return res[0];
}
public int getHeight(Node head, int level, boolean[] res) {
if (head == null) {
return level;
}
int LH = getHeight(head.left, level + 1, res);
if (!res[0]) {
return level;
}
int RH = getHeight(head.right, level + 1, res);
if (!res[0]) {
return level;
}
if (Math.abs(LH - RH) > 1) {
res[0] = false;
}
return Math.max(LH, RH);
}
首先遍历左子树,收集两个信息
1. 左子树是否为平衡二叉树(true or false)
2. 左子树最多到哪一层, LH
如果左子树不是平衡二叉树,直接返回false。
否则遍历右子树,收集两个信息
1.右子树是否为平衡二叉树
2.右子树最多到哪一层, RH
如果右子树不是平衡二叉树,直接返回false。
此时,左右子树都是平衡二叉树,
考察LH,RH的差值是否大于1
大于1,不是平衡二叉树,返回false
不大于1,返回左右子树深度的最大值。
案例五:判断一棵树是否是搜索二叉树
给定一棵二叉树的头结点head,判断这棵树是否是搜索二叉树
答案:
1.改写二叉树的中序遍历
2.遍历到每个节点的值时,如果一直比上一个遍历的节点值要大,则是搜索二叉树,否则不是搜索二叉树
3.为了方便同时得到当前节点,和上一个遍历的节点,二叉树中中序遍历使用非递归比较合适。
案例六:判断一棵树是否是完全二叉树
给定一棵树的头结点head,判断一棵树是否是完全二叉树
答案:
1.采用层次遍历方式,从每层的左边向右边依次遍历所有节点
2.如果当前结果有右孩子,但没有左孩子,直接返回false
3.如果当前节点并不是左右孩子全有,那之后的节点必须都为叶节点,否则返回false
4.遍历过程中如果不返回false,遍历结束后直接返回true
案例七:求二叉树节点的后继节点
给定新的节点类型,构成新的二叉树,每个节点的parent指向父节点,头结点的parent指向空。
给定二叉树中的某个节点node,该节点并不一定是头结点,可能是树中任何一个节点。
实现返回node的后继节点的函数。
public class Node {
int value;
Node left;
Node right;
Node parent;
public Node(int data) {
this.value = data;
}
}
后继节点与前驱节点
后继节点:一个节点的后继节点是指,这个节点在中序遍历序列中的下一个节点。
前驱节点:一个节点的前驱节点是指,这个节点在中序遍历序列中的上一个节点。
答案:
普通方法:时间复杂度O(N),空间复杂度O(N)
1.通过node的parent不断向上找到头结点
2.通过找到的头结点,进行中序遍历,生成中序遍历序列
3.中序遍历序列中,node节点的下一个节点,就是后继节点
最优解:(其实就是分析中序遍历)
如果node节点和node后继节点之间的实际距离为L,最优解只用走过L个节点,
时间复杂度为O(L),空间复杂度为O(1)
具体过程:
情况1:如果node节点有右子树,node节点的后继节点为右子树上最左边的节点
情况2:如果node节点没有右子树,那个先看node是不是node头结点的左孩子,
如果是左孩子,node的父节点就是node的后继节点
如果是右孩子,就向上找node的后继节点,假设向上移动到的节点记为s,s的父节点记为p,如果发现s是p的左孩子,那么节点p就是node的后继节点,否则一直向上移动
案例八:折纸对折N次,从上到下打印所用折痕的方向
折纸,每次从下向上折
对折一次,从上到下产生的折痕为下
对折两次,从上到下产生的折痕为下下上
对折三次,从上到下产生的折痕为.............
给定对折次数N,从上到下打印所有折痕的方向
答案:
折痕方向构成了一棵树
下
/ \
上 下
/ \ / \
上 下 上 下
(下方向).........................(上方向)
(右,根,左)的遍历顺序,就是所有折痕的打印顺序。
案例九:找出搜索二叉树中的错误节点
一棵二叉树原本是搜索二叉树,但是其中有两个节点调换了位置,使得这棵二叉树不再是搜索二叉树。
要求找出这两个错误节点。
答案:
1.对二叉树进行中序遍历,依次出现的节点会一直升序,如果两个节点的位置错了,一定会出现降序
2.第一个错误节点为第一次降序的比较大的节点,第二个错误节点为最后一次降序时较小的节点
3.改写二叉树的中序遍历即可
【分析如下:
1.如果在中序遍历时节点值出现了两次降序,
第一个错误的节点为第一次降序时较大的节点
第二个错误的节点为第二次降序时较小的节点
如,原为1,2,3,4,5,交换2,5后变为为1,5,3,4,2
2.如果在中序遍历时只出现了一次降序
第一个错误的节点为降序时较大的节点
第二个错误的节点为降序时较小的节点
如,原为1,2,3,4,5,交换3,4变为1,2,4,3,5】
案例十:节点间的最大距离
从二叉树的节点A出发,可以向上走或者向下走,但沿途的节点只能经过一次,当到达节点B时,路径上的节点数叫做A到B的距离,比如
节点4和节点2的距离为2,节点5和节点6的距离为5,给定一棵二叉树的头结点head,求整棵树上节点间的最大距离
答案:
一个以h为头的树上,最大距离只可能来自以下三种情况:
情况1:h的左子树上的最大距离(左子树)
情况2:h的右子树上的最大距离(右子树)
情况3:h左子树上离h左孩子最远的距离,加上h自身这个节点,再加上h右子树上离h右孩子的最远距离。(分别来自左右子树)
三个值中最大的值就是以h为头的整棵树上最远的距离
具体过程:
1.整个过程为后序遍历,在二叉树的每颗子树上都执行步骤2
2.假设子树头结点为h,
处理h的左子树,得到两个信息,左子树上的最大距离记为Lmax1,左子树上距离h左孩子的最远距离记为Lmax2.
处理h的右子树,得到两个信息,右子树上的最大距离记为Rmax1,右子树上距离h右孩子的最远距离记为Rmax2
跨h节点的情况下的最远距离为Lmax2+1+Rmax2,
这个值与Lmax1和Rmax1比较,最大值为以h为头的最大距离
3.Lmax2+1就是h左子树上距离h最远的点到h的距离
Rmax2+1就是h右子树上距离h最远的点到h的距离,
选两者中最大的一个作为h树上距离h最远的距离返回
4.用返回长度为2的数组的方式,可以做到返回两个值
案例十一:最大搜索二叉子树
给定一棵二叉树的头结点head,已知其中所有节点的值都不一样,找到含有节点最多的搜索二叉子树,并返回这颗子树的头结点。例如,右边的树为左边的数的最大二叉子树。
答案:
---------------------------------------------------------------------------------------------------
我想到的一种方法,利用二叉树的中序和先序遍历
1.先求二叉树的中序遍历:0,1,3,6,2,4,5,10,11,14,15,12,20,13,16
2.在中序遍历中找最长的递增序列,记为A,为2,4,5,10,11,14,15,找到根即可
3.对二叉树进行先序遍历,遍历过程中,看是否当前节点是否在A中,是,找到了根,返回即可
该想法未经验证是否可行,而且时间复杂度有点高O(N^2),N为二叉树的节点个数
---------------------------------------------------------------------------------------------------
以节点node为头的树中,最大的搜索二叉子树只可能来自以下两种情况:
1.来自node左子树上的最大搜索二叉子树是以node左孩子为头的,
并且来自node右子树上的最大搜索二叉子树是以node右孩子为头的,
node左子树上的最大搜索二叉子树的最大值小于node的节点值,
node右子树上的最大搜索二叉子树的最小值大于node的节点值,
那么以节点node为头的整棵树都是搜索二叉树
2.如果不满足第一种情况,说明以节点node为头的树整体不能练成搜索二叉树。
这种情况下,以node为头的树上的最大搜索二叉子树是
来自node的左子树上的最大搜索二叉子树和
来自node的右子树上的最大搜索二叉子树之间,节点数较多的那个
具体过程:
1.整体过程是二叉树的后序遍历
2.遍历到当前节点记为cur时,
先遍历cur的左子树并收集4个信息,分别是左子树上最大搜索二叉子树的头结点、节点数、树上最小值和树上最大值,
再遍历cur的右子树并收集4个信息,分别是右子树上最大搜索二叉子树的头结点、节点数、最小值和最大值
3.根据步骤2所收集的信息,判断是否满足第一种情况,如果满足,返回cur节点;
如果满足第二种情况,就返回左子树和右子树各自的最大搜索二叉子树中,节点数较多的那个树的头结点
4.对于如何返回4个信息,可以使用全局变量更新的方式或长度为4的数组的方式