这是本系列的第二篇,与前一篇 面试大总结之一:Java搞定面试中的链表题目 相比,二叉树的题目可以变化的就更多了。本文还是参考整合重写了《轻松搞定面试中的二叉树题目》和《算法大全(3) 二叉树》两篇大作。本文一个小亮点就是几乎每一道题都用了递归和迭代两种方法写过一遍,因为面试时往往可能会被要求写不擅长的那一种。这一千多行的记录也是我在面试摸索过程中的一个小笔记,备份与此。请大神们轻拍指正。今后我也会不断更新加入新题新方法。
package BinaryTreeSummary;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Stack;
/**
* http://blog.csdn.net/luckyxiaoqiang/article/details/7518888 轻松搞定面试中的二叉树题目
* http://www.cnblogs.com/Jax/archive/2009/12/28/1633691.html 算法大全(3) 二叉树
*
* TODO: 一定要能熟练地写出所有问题的递归和非递归做法!
*
* 1. 求二叉树中的节点个数: getNodeNumRec(递归),getNodeNum(迭代)
* 2. 求二叉树的深度: getDepthRec(递归),getDepth
* 3. 前序遍历,中序遍历,后序遍历: preorderTraversalRec, preorderTraversal, inorderTraversalRec, postorderTraversalRec
* (https://en.wikipedia.org/wiki/Tree_traversal#Pre-order_2)
* 4.分层遍历二叉树(按层次从上往下,从左往右): levelTraversal, levelTraversalRec(递归解法!)
* 5. 将二叉查找树变为有序的双向链表: convertBST2DLLRec, convertBST2DLL
* 6. 求二叉树第K层的节点个数:getNodeNumKthLevelRec, getNodeNumKthLevel
* 7. 求二叉树中叶子节点的个数:getNodeNumLeafRec, getNodeNumLeaf
* 8. 判断两棵二叉树是否相同的树:isSameRec, isSame
* 9. 判断二叉树是不是平衡二叉树:isAVLRec
* 10. 求二叉树的镜像(破坏和不破坏原来的树两种情况):mirrorRec, mirrorCopyRec
* 10.1 判断两个树是否互相镜像:isMirrorRec
* 11. 求二叉树中两个节点的最低公共祖先节点:getLastCommonParent, getLastCommonParentRec, getLastCommonParentRec2
* 12. 求二叉树中节点的最大距离:getMaxDistanceRec
* 13. 由前序遍历序列和中序遍历序列重建二叉树:rebuildBinaryTreeRec
* 14.判断二叉树是不是完全二叉树:isCompleteBinaryTree, isCompleteBinaryTreeRec
*
*/
public class Demo {
/*
1
/ \
2 3
/ \ \
4 5 6
*/
public static void main(String[] args) {
TreeNode r1 = new TreeNode(1);
TreeNode r2 = new TreeNode(2);
TreeNode r3 = new TreeNode(3);
TreeNode r4 = new TreeNode(4);
TreeNode r5 = new TreeNode(5);
TreeNode r6 = new TreeNode(6);
r1.left = r2;
r1.right = r3;
r2.left = r4;
r2.right = r5;
r3.right = r6;
// System.out.println(getNodeNumRec(r1));
// System.out.println(getNodeNum(r1));
// System.out.println(getDepthRec(r1));
// System.out.println(getDepth(r1));
// preorderTraversalRec(r1);
// System.out.println();
// preorderTraversal(r1);
// System.out.println();
// inorderTraversalRec(r1);
// System.out.println();
// inorderTraversal(r1);
// System.out.println();
// postorderTraversalRec(r1);
// System.out.println();
// postorderTraversal(r1);
// System.out.println();
// levelTraversal(r1);
// System.out.println();
// levelTraversalRec(r1);
// System.out.println();
// TreeNode tmp = convertBSTRec(r1);
// while(true){
// if(tmp == null){
// break;
// }
// System.out.print(tmp.val + " ");
// if(tmp.right == null){
// break;
// }
// tmp = tmp.right;
// }
// System.out.println();
// while(true){
// if(tmp == null){
// break;
// }
// System.out.print(tmp.val + " ");
// if(tmp.left == null){
// break;
// }
// tmp = tmp.left;
// }
// TreeNode tmp = convertBST2DLL(r1);
// while(true){
// if(tmp == null){
// break;
// }
// System.out.print(tmp.val + " ");
// if(tmp.right == null){
// break;
// }
// tmp = tmp.right;
// }
// System.out.println(getNodeNumKthLevelRec(r1, 2));
// System.out.println(getNodeNumKthLevel(r1, 2));
// System.out.println(getNodeNumLeafRec(r1));
// System.out.println(getNodeNumLeaf(r1));
// System.out.println(isSame(r1, r1));
// inorderTraversal(r1);
// System.out.println();
// mirror(r1);
// TreeNode mirrorRoot = mirrorCopy(r1);
// inorderTraversal(mirrorRoot);
System.out.println(isCompleteBinaryTree(r1));
System.out.println(isCompleteBinaryTreeRec(r1));
}
private static class TreeNode {
int val;
TreeNode left;
TreeNode right;
public TreeNode(int val) {
this.val = val;
}
}
/**
* 求二叉树中的节点个数递归解法: O(n)
* (1)如果二叉树为空,节点个数为0
* (2)如果二叉树不为空,二叉树节点个数 = 左子树节点个数 +
* 右子树节点个数 + 1
*/
public static int getNodeNumRec(TreeNode root) {
if (root == null) {
return 0;
} else {
return getNodeNumRec(root.left) + getNodeNumRec(root.right) + 1;
}
}
/**
* 求二叉树中的节点个数迭代解法O(n):基本思想同LevelOrderTraversal,
* 即用一个Queue,在Java里面可以用LinkedList来模拟
*/
public static int getNodeNum(TreeNode root) {
if(root == null){
return 0;
}
int count = 1;
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.add(root);
while(!queue.isEmpty()){
TreeNode cur = queue.remove(); // 从队头位置移除
if(cur.left != null){ // 如果有左孩子,加到队尾
queue.add(cur.left);
count++;
}
if(cur.right != null){ // 如果有右孩子,加到队尾
queue.add(cur.right);
count++;
}
}
return count;
}
/**
* 求二叉树的深度(高度) 递归解法: O(n)
* (1)如果二叉树为空,二叉树的深度为0
* (2)如果二叉树不为空,二叉树的深度 = max(左子树深度, 右子树深度) + 1
*/
public static int getDepthRec(TreeNode root) {
if (root == null) {
return 0;
}
int leftDepth = getDepthRec(root.left);
int rightDepth = getDepthRec(root.right);
return Math.max(leftDepth, rightDepth) + 1;
}
/**
* 求二叉树的深度(高度) 迭代解法: O(n)
* 基本思想同LevelOrderTraversal,还是用一个Queue
*/
public static int getDepth(TreeNode root) {
if(root == null){
return 0;
}
int depth = 0;