目录
12.输入一个二叉树和一个整数,打印出二叉树中节点值的和等于输入整数所有的路径
14.从前序与中序遍历序列构造二叉树以及从中序与后序遍历序列构造二叉树
二叉树相关性质
性质1:在二叉树的第 i 层上至多有 2^(i-1)个 结点(i>=1)
性质2:深度为k的二叉树至多有2^k-1个结点(k≥1)。
性质3:在任意-棵二叉树中,若终端结点的个数为n0,度为2的结点数为n2,则no=n2+1。
性质4:具有n个结点的完全二叉树深度为[log2 n]+1.([x]表示不大于x的最大整数)。
性质5:若对一棵有n个结点的完全二叉树(其深度为[log2 n]+1)的结点按层序编号(从第1层到第[log2 n]+1层,每层从左到右),对任一结点i(1<=i<=n):
-
若有i=1,则结点i是二叉树的根,无双亲;若i>1,则其双亲是结点[i/2];
-
若有2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩子是结点2i。
-
若2i+1>n,则结点i无右孩子,否则其右孩子是结点2i+1。
1.求二叉树的最大深度
这里给出两种版本,一种采用递归的做法,整体比较简单,另一种采用非递归的层次遍历来求解高度
递归版本
public int getMaxDepth1(TreeNode root) {
if (root == null) {
return 0;
}
int lDepth=getMaxDepth1(root.left);
int rDepth=getMaxDepth1(root.right);
return Math.max(lDepth,rDepth)+1;
}
非递归版本
public int getMaxDepth2(TreeNode root) {
if (root == null) {
return 0;
}
Queue<TreeNode> queue=new LinkedList<>();
queue.add(root);
int level=0;
while(!queue.isEmpty()) {
int count=0;
int size=queue.size();
while(count<size) { //遍历某一层
TreeNode cur=queue.poll();
count++;
if(cur.left!=null) {
queue.add(cur.left);
}
if(cur.right!=null) {
queue.add(cur.right);
}
}
//遍历完一层以后level+1
level++;
}
return level;
}
2.求二叉树的最小深度
public int getMinDepth(TreeNode root) {
if(root==null) {
return 0;
}
return getMin(root);
}
private int getMin(TreeNode root) {
// TODO Auto-generated method stub
if(root==null) {
return Integer.MAX_VALUE;
}
if(root.left==null&&root.right==null) {
return 1;
}
return Math.min(getMin(root.left),getMin(root.right))+1;
}
3.求二叉树中节点的个数
public static int getNodeNum(TreeNode root) {
if(root==null) {
return 0;
}
int left=getNodeNum(root.left);
int right=getNodeNum(root.right);
return left+right+1;
}
4.求二叉树中的叶子节点的个数
public static int getLeafNum(TreeNode root) {
if(root==null) {
return 0;
}
if(root.left==null&&root.right==null) {
return 1;
}
int left=getLeafNum(root.left);
int right=getLeafNum(root.right);
return left+right;
}
5.求二叉树中第k层节点的个数
public static void getKthNode(TreeNode root,int k) {
if (root == null) {
System.out.println(0);
}
Queue<TreeNode> queue=new LinkedList<>();
queue.add(root);
int level=1;
while(!queue.isEmpty()) {
int count=0;
int size=queue.size();
if(level==k) {
System.out.println(size);
}
while(count<size) { //遍历某一层
TreeNode cur=queue.poll();
count++;
if(cur.left!=null) {
queue.add(cur.left);
}
if(cur.right!=null) {
queue.add(cur.right);
}
}
//遍历完一层以后level+1
level++;
}
}
6.判断二叉树是否是平衡二叉树
public boolean isBalance(TreeNode root) {
if(root==null) {
return true;
}
int left=getDepth(root.left);
int right=getDepth(root.right);
if(Math.abs(left-right)>1) {
return false;
}
return isBalance(root.left)&&isBalance(root.right);
}
private int getDepth(TreeNode root) {
// TODO Auto-generated method stub
if(root==null) {
return 0;
}
return Math.max(getDepth(root.left), getDepth(root.right))+1;
}
7.判断是否完全二叉树
/*
* 按层遍历二叉树, 从每层从左向右遍历所有的结点
如果当前结点有右孩子, 但没有左孩子, 那么直接返回false
如果当前结点并不是左右孩子都有, 那么它之后的所有结点都必须为叶子结点, 否则返回false
遍历结束后返回true
*/
public boolean isCompleteBinaryTree(TreeNode root) {
//定义一个队列
Queue<TreeNode> queue=new LinkedList<TreeNode>();
queue.add(root);
boolean isLeaf=false;
while(!queue.isEmpty()) {
TreeNode cur=queue.poll();
TreeNode left=cur.left;
TreeNode right=cur.right;
//判断叶节点的阶段开启了
if(isLeaf&&(left!=null||right!=null)) {
return false;
}
if(left!=null) {
queue.add(left);
}
if(right!=null) {
queue.add(right);
}
else {
isLeaf=true;
}
}
return true;
}
8.判断是否相同的二叉树
public boolean isSameTreeNode(TreeNode t1,TreeNode t2) {
if(t1==null&&t2==null){
return true;
}
else if(t1==null||t2==null){
return false;
}
if(t1.val != t2.val){
return false;
}
boolean left = isSameTreeNode(t1.left,t2.left);
boolean right = isSameTreeNode(t1.right,t2.right);
return left&&right;
}
9.判断是否是互为镜像的二叉树
public boolean isMirrorTreeNode(TreeNode t1,TreeNode t2) {
if(t1==null&&t2==null){
return true;
}
else if(t1==null||t2==null){
return false;
}
if(t1.val != t2.val){
return false;
}
boolean left = isMirrorTreeNode(t1.left,t2.right);
boolean right = isMirrorTreeNode(t1.right,t2.left);
return left&&right;
}
10.翻转二叉树or镜像二叉树
public TreeNode mirrorTree(TreeNode root) {
if(root==null) {
return root;
}
TreeNode left=mirrorTree(root.left);
TreeNode right=mirrorTree(root.right);
root.left=right;
root.right=left;
return root;
}
11.求两个二叉树的最低公共祖先节点
/*
* 通过路径找最低公共祖先,
* 于是原问题转化为=>寻找二叉树中根节点到指定节点的路径(需要利用回溯的思想)+寻找链表最后一个公共节点的问题。
*/
/*
* 获取两个节点的最低公共祖先
*/
public static TreeNode getLastCommonParent(TreeNode root, TreeNode p1, TreeNode p2) {
//path1和path2分别存储根节点到p1和p2的路径(不包括p1和p2)
List<TreeNode> path1 = new ArrayList<TreeNode>();
List<TreeNode> path2 = new ArrayList<TreeNode>();
List<TreeNode> tmpList = new ArrayList<TreeNode>();
getNodePath(root, p1, path1,tmpList);
getNodePath(root, p2, path2,tmpList);
//如果路径不存在,返回空
if (path1.size() == 0 || path2.size() == 0)
return null;
return getLastCommonParent(path1, path2);
}
// 获取根节点到目标节点的路径
public static void getNodePath(TreeNode root, TreeNode target, List<TreeNode> path,List<TreeNode> tmpList) {
//鲁棒性
if (root == null)
return;
tmpList.add(root);
if(root==target) {
path.addAll(tmpList);
}
//递归左右孩子节点
if(root.left!=null) {
getNodePath(root.left,target,path,tmpList);
}
if(root.right!=null) {
getNodePath(root.right,target,path,tmpList);
}
tmpList.remove(tmpList.size() - 1);
}
//将问题转化为求链表最后一个共同节点
private static TreeNode getLastCommonParent(List<TreeNode> p1, List<TreeNode> p2) {
TreeNode tmpNode = null;
for (int i = 0; i < p1.size(); i++) {
if (p1.get(i) != p2.get(i))
break;
tmpNode = p1.get(i);
}
return tmpNode;
}
12.输入一个二叉树和一个整数,打印出二叉树中节点值的和等于输入整数所有的路径
ArrayList<ArrayList<Integer>> list=new ArrayList<ArrayList<Integer>>();
public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
ArrayList<Integer> list1=new ArrayList<>();
getPath(root, target, list1);
return list;
}
public void getPath(TreeNode root, int target, ArrayList<Integer> list1){
if(root==null|| target<0) return;
list1.add(root.val);
if(target-root.val==0 && root.left==null && root.right==null){
list.add(new ArrayList<Integer> (list1));
}
getPath(root.left, target-root.val, list1);
getPath(root.right, target-root.val, list1);
list1.remove(list1.size()-1);
}
13.打印所以根节点到叶节点的路径
public static List<String> binaryTreePaths(TreeNode root) {
List<String> path=new ArrayList<>();
if(root==null){
return path;
}
getAllPath(root,path,"");
return path;
}
public static void getAllPath(TreeNode root,List<String> path,String str){
str+=root.val+" ";
if(root.left==null&&root.right==null){
path.add(str.trim().replace(" ", "->"));
return;
}
if(root.left!=null) {
getAllPath(root.left,path,str);
}
if(root.right!=null) {
getAllPath(root.right,path,str);
}
}
14.从前序与中序遍历序列构造二叉树以及从中序与后序遍历序列构造二叉树
这里只给出通过前序与中序遍历构造二叉树的解答,从中序和后序遍历构造二叉树类似
整体分为几个步骤:
1.找根节点
2.找左子树范围,右子树范围
3.不断递归,直到左子树的范围或右子树范围缩减到1
package 二叉树问题;
public class BuildTree {
public TreeNode buildTree(int[] preorder, int[] inorder) {
return test(preorder,0,preorder.length-1,inorder,0,inorder.length-1);
}
private TreeNode test(int[] preorder, int p, int q, int[] inorder, int i, int j) {
//递归终止的条件
if (p > q) return null;
TreeNode node = new TreeNode(preorder[p]);
int k = i;
// 找到根节点在中序遍历序列中的位置
while (preorder[p] != inorder[k]) {
k++;
}
//p+1~p+k-i 先序遍历中左子树范围
//i~k-1 中序遍历中左子树范围
node.left = test(preorder, p+1, p+k-i, inorder, i, k-1);
node.right = test(preorder, p+k-i+1, q, inorder, k+1, j);
return node;
}
}
15.序列化和反序列化二叉树
序列化
public static String serializableTree(TreeNode root) {
//利用先序遍历来进行二叉树的序列化
String res="";
return pre(root,res);
}
private static String pre(TreeNode root, String res) {
// TODO Auto-generated method stub
if(root==null) {
res+="#!";
return res;
}
res+=root.val+"!";
res+=serializableTree(root.left);
res+=serializableTree(root.right);
return res;
}
反序列化
public static TreeNode reserializableTree(String res) {
//利用先序遍历来进行二叉树的反序列化
String[] str=res.split("!");
Queue<String> queue=new LinkedList<>();
for(int i=0;i<str.length;i++) {
queue.offer(str[i]);
}
return reconPre(queue);
}
private static TreeNode reconPre(Queue<String> queue) {
// TODO Auto-generated method stub
String val=queue.poll();
if(val.equals("#")) {
return null;
}
TreeNode head=new TreeNode(Integer.valueOf(val));
head.left=reconPre(queue);
head.right=reconPre(queue);
return head;
}
16.判断一棵二叉树是否是对称二叉树
public class IsSymmetrical {
boolean isSymmetrical(TreeNode pRoot)
{
if(pRoot==null) {
return true;
}
return isSymmertrical(pRoot,pRoot);
}
private boolean isSymmertrical(TreeNode pRoot1, TreeNode pRoot2) {
// TODO Auto-generated method stub
if(pRoot1==null&&pRoot2==null) {
return true;
}
if(pRoot1==null||pRoot2==null) {
return false;
}
if(pRoot1.val!=pRoot2.val) {
return false;
}
return isSymmertrical(pRoot1.left,pRoot2.right)&&isSymmertrical(pRoot1.right,pRoot2.left);
}
}
持续更新中,以后刷题过程中遇到二叉树的题都会整理到这篇博文中。