7.重建二叉树
**题目描述:**输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如输入前序遍
历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回
:
前序遍历特点:第一个值是根节点 (根左右)
中序遍历特点:根节点左边都是左子树,右边都是右子树(左根右)
/**
* Definition for binary tree
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
import java.util.*;
public class Solution {
public TreeNode buildTree(int [] pre,int [] in) {
if(pre==null||in==null||pre.length==0||in.length==0){
return null;
}
int index=findindex(pre,in);
//1.获取到树的根节点的value值
TreeNode root=new TreeNode(pre[0]);
//2.构建left左子树、right右子树
//root.left=buildTree(左子树的前序数组,左子树的中序数组);
root.left=buildTree(Arrays.copyOfRange(pre,1,index+1),
Arrays.copyOfRange(in,0,index));
//root.right=buildTree(右子树的前序数组,右子树的中序数组);
root.right=buildTree(Arrays.copyOfRange(pre,index+1,pre.length),
Arrays.copyOfRange(in,index+1,in.length));
return root;
}
//构造一个找根节点下标的函数findindex
public int findindex(int [] pre,int [] in){
for(int i=0;i<in.length;i++){
if(in[i]==pre[0]){
return i;
}
}
return 0;
}
}
Arrays提供了一个copyOfRange方法进行数组复制
copyOfRange(int[] original, int from, int to)
将一个原始的数组original,从下标from开始复制,复制到上标to,生成一个新的数组。注意这里包括下标from,不包括上标to(Array.copyOfRange的方法是左闭右开的)
8.二叉树的下一个节点
**题目描述:**给定一个二叉树和其中的一个节点,请找出中序遍历顺序的下一个节点并且返回。注意,树中的节点不仅包含左右子节点,同时包含指向父节点的指针。
:
中序遍历结果{d,b,h,e,i,a,f,c,g}
1.如果当前结点有右子树
• 下一个节点就是它的右子树的最左子节点(从右子节点出发一致沿着指向左子节点的指针,即可找到)
如:b—>h, a—>f
2.如果当前节点没有右子树
• 如果当前节点是它父节点的左子节点,下一个节点就是它的父节点
如:d—>b, f—>c, h—>e
• 如果当前节点是它父节点的右子节点
沿着指向父节点的指针一直向上遍历,直到找到一个是它父节点的左子节点的节点,如果这样的节点存在,那么这个节点的父节点就是我们要找到的下一个节点
如:i节点的下一个节点:沿着指向父节点的指针向上遍历,先到e,e是b的右子节点,不是,继续向上遍历,到b, b是a的左子节点,因此节点b的父节点a就是i的下一个节点
如:g节点的下一个节点:沿着指向父节点的指针向上遍历,先到c, c是a的右子节点,不是,继续向上遍历到a, a是根节点,无父节点,因此g没有下一个节点
/**
*public class TreeLinkNode {
* int val;
* TreeLinkNode left = null;
* TreeLinkNode right = null;
* TreeLinkNode next = null; //父节点指针
*
* TreeLinkNode(int val) {
* this.val = val;
* }
* }
**/
public class Solution {
public TreeLinkNode getNext(TreeLinkNode pNode)
{
if (pNode == null) {
return null;
}
// 右节点不为空
if (pNode.right != null) {
pNode = pNode.right;
while (pNode.left != null) {
pNode = pNode.left;
}
return pNode;
}
// 右节点为空,父节点不为空
while (pNode.next != null) {
// 当前节点是父节点的左孩子则返回父节点
if(pNode.next.left == pNode) {
return pNode.next;
}
// 当前节点不是父节点的左孩子,向上找父节点,重复此过程
pNode = pNode.next;
}
// 其他情况返回null
return null;
}
}
:主要是分为三种情况:
• 第一种情况就是pNode节点有右孩子时,那么pNode的下一个节点就是右孩子对应的那颗子树的最左侧的节点;
• 如果说当前节点的右孩子为空,并且pNode是pNode父亲节点的左孩子,那么直接返回pNode的父亲节点即可;
• 如果说当前节点的右孩子为空,并且pNode是pNode父亲节点的右孩子那么就返回pNode节点的爷爷节点。
• 当然还有些特殊情况,比如说:二叉树的最右侧节点的判断,以及父亲节点是否为空的判断。
public class Solution {
public TreeLinkNode GetNext(TreeLinkNode pNode) {
if (pNode.right != null) {
// 第一种情况,pNode节点的右孩子不为空
pNode = pNode.right; //把图中a节点移到c节点
while (pNode.left != null) { //如果c节点的左节点不为空
pNode = pNode.left;
}
return pNode;
} else {
TreeLinkNode tempNode = pNode.next;
if (tempNode == null) { //情况对应下图,父节点不能为空
return null;
}
if (tempNode.left == pNode) {
// 第二种情况,当前节点右孩子为空,并且当前节点是父亲节点的左孩子
return tempNode;
} else {
// 第二种情况,当前节点右孩子为空,并且当前节点是父亲节点的右孩子
boolean flag = false;
while (tempNode.next != null) {
if (tempNode.next.left == tempNode) {
flag = true;
break;
}
tempNode = tempNode.next;
}
return flag ? tempNode.next : null; // flag尾true时,
说明pNode所指的节点不是二叉树中最右侧节点(如图中g)
}
}
}
}
26.树的子结构
**题目描述:**输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
B是A的子结构, 即 A中有出现和B相同的结构和节点值
:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isSubStructure(TreeNode A, TreeNode B) {
if(A==null||B==null){
return false;
}
return helper(A,B)||isSubStructure(A.left,B)||isSubStructure(A.right,B);
}
public boolean helper(TreeNode A, TreeNode B){
if(B==null){ //B为null,说明从上往下递归遍历,B已经遍历结束了,而A并没有跳出,说明B是A的子结构
return true;
}
if(A==null){//B到这步没有跳出说明不为null,而此时A为null,说明从上往下递归遍历,
A已经遍历结束了,说明B不是A的子结构
return false;
}
return A.val==B.val&&helper(A.left,B.left)&&helper(A.right,B.right);
}
}
27、二叉树的镜像
**题目描述:**请完成一个函数,输入一棵二叉树,该函数输出它的镜像
:
从下往上互换,1-3,6-9再到2-7互换,递归思路为互换2-7时假定1-3,6-9已经互换
/* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode mirrorTree(TreeNode root) {
if(root==null) { //当前root没有左右子树
return root;
}
//获取反转过的子树
TreeNode left=mirrorTree(root.left); //此时left是子树互换过后的左节点
TreeNode right=mirrorTree(root.right); //此时right是子树互换过后的右节点
//左右互换
root.right=left; //把原先右节点换成反转过子树的左节点
root.left=right; //把原先左节点换成反转过子树的右节点
return root;
}
}
28.对称的二叉树
**题目描述:**请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
:
本题:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root==null){
return true;
}
return helper(root.left,root.right);
}
public boolean helper(TreeNode A, TreeNode B){
//边界条件,递归出口
if(A==null&&B==null){return true;}
if(A==null||B==null){return false;}
return A.val==B.val && helper(A.left,B.right) && helper(A.right,B.left);
}
}
32.从上到下打印二叉树
题目描述:从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。
:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int[] levelOrder(TreeNode root) {
if(root==null){return new int[]{};} //如果root为空,返回一个空数组
//两种数据结构 Queue + List,前者用来先进先出,后者用来接收结果
Queue<TreeNode> queue=new LinkedList<>();
ArrayList<Integer> list =new ArrayList<>();
//首先将根节点加入队列中
queue.add(root);
//核心方案:queue中取出一个元素放入list,再把其左右孩子放入queue
while(!queue.isEmpty()){
TreeNode node=queue.remove(); //queue中取出一个节点
list.add(node.val); //把节点值放入list中
//左右孩子不空,放入queue中
if(node.left!=null){ queue.add(node.left);}
if(node.right!=null){ queue.add(node.right);}
}
//题目要求返回int[]数组,于是把ArrayList类型转换为int[]数组
int[] res=new int[list.size()];
for(int i=0;i<list.size();i++){
res[i]=list.get(i);
}
return res;
}
}
实现了Queue接口,因此我们可以把LinkedList当成Queue来用
Queue的常用方法:
将指定的元素插入此队列
获取并移除此队列的头
List的常用方法:
: 向列表的尾部添加指定的元素
: 返回列表中的元素个数
: 返回列表中指定位置的元素,index从0开始
题目描述:从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。
:
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res=new ArrayList<>();
if(root==null){return res;} //如果root为空,返回一个空的res
Queue<TreeNode> queue=new LinkedList<>();
//首先将根节点加入队列中
queue.add(root);
while(!queue.isEmpty()){
ArrayList<Integer> temp=new ArrayList<>();
int size=queue.size(); //遍历某一层,先获取该层的size,先获得queue.size(),防止fast fail
for(int i=0;i<size;i++){ //每个for循环完成一层的遍历。不能写i<queue.size;因为size是动态数值
TreeNode node=queue.remove(); //queue中取出一个节点
temp.add(node.val); //把一层所有的值加入temp中
//左右孩子不空,放入queue中
if(node.left!=null){ queue.add(node.left);}
if(node.right!=null){ queue.add(node.right);}
}
res.add(temp); //把每一层结果放到res中
}
return res;
}
}
返回队列中元素的个数(二叉树的一层为一个queue)
题目描述:请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
:
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res=new ArrayList<>();
if(root==null){return res;} //如果root为空,返回一个空的res
Queue<TreeNode> queue=new LinkedList<>();
queue.add(root); //首先将根节点加入队列中
boolean flag=true; //首次默认尾部添加,true
while(!queue.isEmpty()){
List<Integer> temp =new LinkedList<>(); //LinkedList添加元素更快
//ArrayList<Integer> temp=new ArrayList<>();
int size=queue.size(); //遍历某一层,先获取该层的size,先获得queue.size(),防止fast fail
for(int i=0;i<size;i++){ //每个for循环完成一层的遍历
TreeNode node=queue.remove(); //queue中取出一个节点
if(flag){
temp.add(node.val); //奇数行,List中尾部添加
}
else{
temp.add(0,node.val); //偶数行,List中头部插入
}
//左右孩子不空,放入queue中
if(node.left!=null){ queue.add(node.left);}
if(node.right!=null){ queue.add(node.right);}
}
flag=!flag; //使得flag循环一次为true,一次为false
res.add(temp); //把每一层结果放到res中
}
return res;
}
}
List的常用方法:
add(Object element): 向列表的尾部添加指定的元素。
add(int index, Object element): 在列表的指定位置插入指定元素
ArrayList底层是数组,头部插入会使得所有元素向后复制一遍;
而LinkedList底层是双向链表,头部插入只需加一个指针和节点即可
:
32.二叉树的深度
**题目描述:**输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
:
一棵树的深度可以认为是它孩子节点深度+1
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
if(root==null){return 0;} //一个节点都没有,深度当然为0
//分别得到了root根节点左右孩子的深度
int l=maxDepth(root.left);
int r=maxDepth(root.right);
if(l>r){
return l+1;
}else{
return r+1;
}
//return Math.max(l+1,r+1);
}
}
class Solution {
public int maxDepth(TreeNode root) {
return root==null?0:Math.max(maxDepth(root.left),maxDepth(root.right))+1;
}
}
平衡二叉树
**题目描述:**给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
:
不仅要考虑根节点的左右高度差的绝对值是否超过1,还要考虑其左右子树的高度差的绝对值是否超过1
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isBalanced(TreeNode root) {
if(root==null){return true;}
int l=maxDepth(root.left);
int r=maxDepth(root.right);
//|l-r|<=1
return (l-r>=-1 && l-r<=1)&& isBalanced(root.left) && isBalanced(root.right);
}
public int maxDepth(TreeNode root) {
if(root==null){return 0;} //一个节点都没有,深度当然为0
//分别得到了root根节点左右孩子的深度
int l=maxDepth(root.left);
int r=maxDepth(root.right);
if(l>r){
return l+1;
}else{
return r+1;
}
//return Math.max(l+1,r+1);
}
}