本文章已收录于:
![](http://static.blog.csdn.net/images/category_icon.jpg)
- package Algorithms.tree;
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Queue;
- import java.util.Stack;
- /**
- * REFS:
- * http://blog.csdn.net/fightforyourdream/article/details/16843303 面试大总结之二:Java搞定面试中的二叉树题目
- * http://blog.csdn.net/luckyxiaoqiang/article/details/7518888 轻松搞定面试中的二叉树题目
- * http://www.cnblogs.com/Jax/archive/2009/12/28/1633691.html 算法大全(3) 二叉树
- *
- * 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
- * mirror, mirrorCopy
- * 10.1 判断两个树是否互相镜像:isMirrorRec isMirror
- * 11. 求二叉树中两个节点的最低公共祖先节点:
- * LAC 求解最小公共祖先, 使用list来存储path.
- * LCABstRec 递归求解BST树.
- * LCARec 递归算法 .
- * 12. 求二叉树中节点的最大距离:getMaxDistanceRec
- * 13. 由前序遍历序列和中序遍历序列重建二叉树:rebuildBinaryTreeRec
- * 14. 判断二叉树是不是完全二叉树:isCompleteBinaryTree, isCompleteBinaryTreeRec
- * 15. 找出二叉树中最长连续子串(即全部往左的连续节点,或是全部往右的连续节点)findLongest
- */
- public class TreeDemo {
- /*
- 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);
- /*
- 10
- / \
- 6 14
- / \ \
- 4 8 16
- /
- 0
- */
- /*
- 1
- / \
- 2 3
- / \ \
- 4 5 6
- */
- // TreeNode r1 = new TreeNode(10);
- // TreeNode r2 = new TreeNode(6);
- // TreeNode r3 = new TreeNode(14);
- // TreeNode r4 = new TreeNode(4);
- // TreeNode r5 = new TreeNode(8);
- // TreeNode r6 = new TreeNode(16);
- TreeNode r7 = new TreeNode(0);
- r1.left = r2;
- r1.right = r3;
- r2.left = r4;
- r2.right = r5;
- r3.right = r6;
- r4.left = r7;
- TreeNode t1 = new TreeNode(10);
- TreeNode t2 = new TreeNode(6);
- TreeNode t3 = new TreeNode(14);
- TreeNode t4 = new TreeNode(4);
- TreeNode t5 = new TreeNode(8);
- TreeNode t6 = new TreeNode(16);
- TreeNode t7 = new TreeNode(0);
- TreeNode t8 = new TreeNode(0);
- TreeNode t9 = new TreeNode(0);
- TreeNode t10 = new TreeNode(0);
- TreeNode t11 = new TreeNode(0);
- t1.left = t2;
- t1.right = t3;
- t2.left = t4;
- t2.right = t5;
- t3.left = t6;
- t3.right = t7;
- t4.left = t8;
- //t4.right = t9;
- t5.right = t9;
- // test distance
- // t5.right = t8;
- // t8.right = t9;
- // t9.right = t10;
- // t10.right = t11;
- /*
- 10
- / \
- 6 14
- / \ \
- 4 8 16
- /
- 0
- */
- // System.out.println(LCABstRec(t1, t2, t4).val);
- // System.out.println(LCABstRec(t1, t2, t6).val);
- // System.out.println(LCABstRec(t1, t4, t6).val);
- // System.out.println(LCABstRec(t1, t4, t7).val);
- // System.out.println(LCABstRec(t1, t3, t6).val);
- //
- // System.out.println(LCA(t1, t2, t4).val);
- // System.out.println(LCA(t1, t2, t6).val);
- // System.out.println(LCA(t1, t4, t6).val);
- // System.out.println(LCA(t1, t4, t7).val);
- // System.out.println(LCA(t1, t3, t6).val);
- // System.out.println(LCA(t1, t6, t6).val);
- //System.out.println(getMaxDistanceRec(t1));
- //System.out.println(isSame(r1, t1));
- // System.out.println(isAVLRec(r1));
- //
- // preorderTraversalRec(r1);
- // //mirrorRec(r1);
- // //TreeNode r1Mirror = mirror(r1);
- //
- // TreeNode r1MirrorCopy = mirrorCopy(r1);
- // System.out.println();
- // //preorderTraversalRec(r1Mirror);
- // preorderTraversalRec(r1MirrorCopy);
- //
- // System.out.println();
- //
- // System.out.println(isMirrorRec(r1, r1MirrorCopy));
- // System.out.println(isMirror(r1, r1MirrorCopy));
- //System.out.println(getNodeNumKthLevelRec(r1, 5));
- //System.out.println(getNodeNumLeaf(r1));
- // System.out.println(getNodeNumRec(null));
- // System.out.println(getNodeNum(r1));
- //System.out.println(getDepthRec(null));
- // System.out.println(getDepth(r1));
- //
- // preorderTraversalRec(r1);
- // System.out.println();
- // preorderTraversal(r1);
- // System.out.println();
- // inorderTraversalRec(r1);
- //
- // System.out.println();
- // inorderTraversal(r1);
- // postorderTraversalRec(r1);
- // System.out.println();
- // postorderTraversal(r1);
- // System.out.println();
- // levelTraversal(r1);
- //
- // System.out.println();
- // levelTraversalRec(r1);
- // TreeNode ret = convertBST2DLLRec(r1);
- // while (ret != null) {
- // System.out.print(ret.val + " ");
- // ret = ret.right;
- // }
- // TreeNode ret2 = convertBST2DLL(r1);
- // while (ret2.right != null) {
- // ret2 = ret2.right;
- // }
- //
- // while (ret2 != null) {
- // System.out.print(ret2.val + " ");
- // ret2 = ret2.left;
- // }
- //
- // TreeNode ret = convertBST2DLL(r1);
- // while (ret != null) {
- // System.out.print(ret.val + " ");
- // ret = ret.right;
- // }
- // System.out.println();
- // System.out.println(findLongest(r1));
- // System.out.println();
- // System.out.println(findLongest2(r1));
- // test the rebuildBinaryTreeRec.
- //test_rebuildBinaryTreeRec();
- System.out.println(isCompleteBinaryTreeRec(t1));
- System.out.println(isCompleteBinaryTree(t1));
- }
- public static void test_rebuildBinaryTreeRec() {
- ArrayList<Integer> list1 = new ArrayList<Integer>();
- list1.add(1);
- list1.add(2);
- list1.add(4);
- list1.add(5);
- list1.add(3);
- list1.add(6);
- list1.add(7);
- list1.add(8);
- ArrayList<Integer> list2 = new ArrayList<Integer>();
- list2.add(4);
- list2.add(2);
- list2.add(5);
- list2.add(1);
- list2.add(3);
- list2.add(7);
- list2.add(6);
- list2.add(8);
- TreeNode root = rebuildBinaryTreeRec(list1, list2);
- preorderTraversalRec(root);
- System.out.println();
- postorderTraversalRec(root);
- }
- private static class TreeNode{
- int val;
- TreeNode left;
- TreeNode right;
- public TreeNode(int val){
- this.val = val;
- left = null;
- right = null;
- }
- }
- /*
- * null返回0,然后把左右子树的size加上即可。
- * */
- public static int getNodeNumRec(TreeNode root) {
- if (root == null) {
- return 0;
- }
- 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;
- }
- Queue<TreeNode> q = new LinkedList<TreeNode>();
- q.offer(root);
- int cnt = 0;
- while (!q.isEmpty()) {
- TreeNode node = q.poll();
- if (node.left != null) {
- q.offer(node.left);
- }
- if (node.right != null) {
- q.offer(node.right);
- }
- cnt++;
- }
- return cnt;
- }
- public static int getDepthRec(TreeNode root) {
- if (root == null) {
- return -1;
- }
- return Math.max(getDepthRec(root.left), getDepthRec(root.right)) + 1;
- }
- /*
- * 可以用 level LevelOrderTraversal 来实现,我们用一个dummyNode来分隔不同的层,这样即可计算出实际的depth.
- * 1
- / \
- 2 3
- / \ \
- 4 5 6
- *
- * 在队列中如此排列: 1, dummy, 2, 3, dummy, 4, 5, 5, dummy
- *
- */
- public static int getDepth(TreeNode root) {
- if (root == null) {
- return 0;
- }
- TreeNode dummy = new TreeNode(0);
- Queue<TreeNode> q = new LinkedList<TreeNode>();
- q.offer(root);
- q.offer(dummy);
- int depth = -1;
- while (!q.isEmpty()) {
- TreeNode curr = q.poll();
- if (curr == dummy) {
- depth++;
- if (!q.isEmpty()) { // 使用DummyNode来区分不同的层, 如果下一层不是为空,则应该在尾部加DummyNode.
- q.offer(dummy);
- }
- }
- if (curr.left != null) {
- q.offer(curr.left);
- }
- if (curr.right != null) {
- q.offer(curr.right);
- }
- }
- return depth;
- }
- /*
- * 3. 前序遍历,中序遍历,后序遍历: preorderTraversalRec, preorderTraversal, inorderTraversalRec, postorderTraversalRec
- * (https://en.wikipedia.org/wiki/Tree_traversal#Pre-order_2)
- * */
- public static void preorderTraversalRec(TreeNode root) {
- if (root == null) {
- return;
- }
- System.out.print(root.val + " ");
- preorderTraversalRec(root.left);
- preorderTraversalRec(root.right);
- }
- /*
- * 前序遍历,Iteration 算法. 把根节点存在stack中。
- * */
- public static void preorderTraversal(TreeNode root) {
- if (root == null) {
- return;
- }
- Stack<TreeNode> s = new Stack<TreeNode>();
- s.push(root);
- while (!s.isEmpty()) {
- TreeNode node = s.pop();
- System.out.print(node.val + " ");
- if (node.right != null) { //
- s.push(node.right);
- }
- // 我们需要先压入右节点,再压入左节点,这样就可以先弹出左节点。
- if (node.left != null) {
- s.push(node.left);
- }
- }
- }
- /*
- * 中序遍历
- * */
- public static void inorderTraversalRec(TreeNode root) {
- if (root == null) {
- return;
- }
- inorderTraversalRec(root.left);
- System.out.print(root.val + " ");
- inorderTraversalRec(root.right);
- }
- /**
- * 中序遍历迭代解法 ,用栈先把根节点的所有左孩子都添加到栈内,
- * 然后输出栈顶元素,再处理栈顶元素的右子树
- * http://www.youtube.com/watch?v=50v1sJkjxoc
- *
- * 还有一种方法能不用递归和栈,基于线索二叉树的方法,较麻烦以后补上
- * http://www.geeksforgeeks.org/inorder-tree-traversal-without-recursion-and-without-stack/
- */
- public static void inorderTraversal(TreeNode root) {
- if (root == null) {
- return;
- }
- Stack<TreeNode> s = new Stack<TreeNode>();
- TreeNode cur = root;
- while(true) {
- // 把当前节点的左节点都push到栈中.
- while (cur != null) {
- s.push(cur);
- cur = cur.left;
- }
- if (s.isEmpty()) {
- break;
- }
- // 因为此时已经没有左孩子了,所以输出栈顶元素
- cur = s.pop();
- System.out.print(cur.val + " ");
- // 准备处理右子树
- cur = cur.right;
- }
- }
- // 后序遍历
- /*
- * 1
- / \
- 2 3
- / \ \
- 4 5 6
- if put into the stack directly, then it should be:
- 1, 2, 4, 5, 3, 6 in the stack.
- when pop, it should be: 6, 3, 5, 4, 2, 1
- if I
- * */
- public static void postorderTraversalRec(TreeNode root) {
- if (root == null) {
- return;
- }
- postorderTraversalRec(root.left);
- postorderTraversalRec(root.right);
- System.out.print(root.val + " ");
- }
- /**
- * 后序遍历迭代解法
- * http://www.youtube.com/watch?v=hv-mJUs5mvU
- * http://blog.csdn.net/tang_jin2015/article/details/8545457
- * 从左到右的后序 与从右到左的前序的逆序是一样的,所以就简单喽! 哈哈
- * 用另外一个栈进行翻转即可喽
- */
- public static void postorderTraversal(TreeNode root) {
- if (root == null) {
- return;
- }
- Stack<TreeNode> s = new Stack<TreeNode>();
- Stack<TreeNode> out = new Stack<TreeNode>();
- s.push(root);
- while(!s.isEmpty()) {
- TreeNode cur = s.pop();
- out.push(cur);
- if (cur.left != null) {
- s.push(cur.left);
- }
- if (cur.right != null) {
- s.push(cur.right);
- }
- }
- while(!out.isEmpty()) {
- System.out.print(out.pop().val + " ");
- }
- }
- /*
- * 分层遍历二叉树(按层次从上往下,从左往右)迭代
- * 其实就是广度优先搜索,使用队列实现。队列初始化,将根节点压入队列。当队列不为空,进行如下操作:弹出一个节点
- * ,访问,若左子节点或右子节点不为空,将其压入队列
- * */
- public static void levelTraversal(TreeNode root) {
- if (root == null) {
- return;
- }
- Queue<TreeNode> q = new LinkedList<TreeNode>();
- q.offer(root);
- while (!q.isEmpty()) {
- TreeNode cur = q.poll();
- System.out.print(cur.val + " ");
- if (cur.left != null) {
- q.offer(cur.left);
- }
- if (cur.right != null) {
- q.offer(cur.right);
- }
- }
- }
- public static void levelTraversalRec(TreeNode root) {
- ArrayList<ArrayList<Integer>> ret = new ArrayList<ArrayList<Integer>>();
- levelTraversalVisit(root, 0, ret);
- System.out.println(ret);
- }
- /**
- * 分层遍历二叉树(递归)
- * 很少有人会用递归去做level traversal
- * 基本思想是用一个大的ArrayList,里面包含了每一层的ArrayList。
- * 大的ArrayList的size和level有关系
- *
- * http://discuss.leetcode.com/questions/49/binary-tree-level-order-traversal#answer-container-2543
- */
- public static void levelTraversalVisit(TreeNode root, int level, ArrayList<ArrayList<Integer>> ret) {
- if (root == null) {
- return;
- }
- // 如果ArrayList的层数不够用, 则新添加一层
- // when size = 3, level: 0, 1, 2
- if (level >= ret.size()) {
- ret.add(new ArrayList<Integer>());
- }
- // visit 当前节点
- ret.get(level).add(root.val);
- // 将左子树, 右子树添加到对应的层。
- levelTraversalVisit(root.left, level + 1, ret);
- levelTraversalVisit(root.right, level + 1, ret);
- }
- /*
- * 题目要求:将二叉查找树转换成排序的双向链表,不能创建新节点,只调整指针。
- 查找树的结点定义如下:
- 既然是树,其定义本身就是递归的,自然用递归算法处理就很容易。将根结点的左子树和右子树转换为有序的双向链表,
- 然后根节点的left指针指向左子树结果的最后一个结点,同时左子树最后一个结点的right指针指向根节点;
- 根节点的right指针指向右子树结果的第一个结点,
- 同时右子树第一个结点的left指针指向根节点。
- * */
- public static TreeNode convertBST2DLLRec(TreeNode root) {
- return convertBST2DLLRecHelp(root)[0];
- }
- /*
- * ret[0] 代表左指针
- * ret[1] 代表右指针
- * */
- public static TreeNode[] convertBST2DLLRecHelp(TreeNode root) {
- TreeNode[] ret = new TreeNode[2];
- ret[0] = null;
- ret[1] = null;
- if (root == null) {
- return ret;
- }
- if (root.left != null) {
- TreeNode left[] = convertBST2DLLRecHelp(root.left);
- left[1].right = root; // 将左子树的尾节点连接到根
- root.left = left[1];
- ret[0] = left[0];
- } else {
- ret[0] = root; // 左节点返回root.
- }
- if (root.right != null) {
- TreeNode right[] = convertBST2DLLRecHelp(root.right);
- right[0].left = root; // 将右子树的头节点连接到根
- root.right = right[0];
- ret[1] = right[1];
- } else {
- ret[1] = root; // 右节点返回root.
- }
- return ret;
- }
- /**
- * 将二叉查找树变为有序的双向链表 迭代解法
- * 类似inOrder traversal的做法
- */
- public static TreeNode convertBST2DLL(TreeNode root) {
- while (root == null) {
- return null;
- }
- TreeNode pre = null;
- Stack<TreeNode> s = new Stack<TreeNode>();
- TreeNode cur = root;
- TreeNode head = null; // 链表头
- while (true) {
- while (cur != null) {
- s.push(cur);
- cur = cur.left;
- }
- // if stack is empty, just break;
- if (s.isEmpty()) {
- break;
- }
- cur = s.pop();
- if (head == null) {
- head = cur;
- }
- // link pre and cur.
- cur.left = pre;
- if (pre != null) {
- pre.right = cur;
- }
- // 左节点已经处理完了,处理右节点
- cur = cur.right;
- pre = cur;
- }
- return root;
- }
- /*
- * * 6. 求二叉树第K层的节点个数:getNodeNumKthLevelRec, getNodeNumKthLevel
- * */
- public static int getNodeNumKthLevel(TreeNode root, int k) {
- if (root == null || k <= 0) {
- return 0;
- }
- int level = 0;
- Queue<TreeNode> q = new LinkedList<TreeNode>();
- q.offer(root);
- TreeNode dummy = new TreeNode(0);
- int cnt = 0; // record the size of the level.
- q.offer(dummy);
- while (!q.isEmpty()) {
- TreeNode node = q.poll();
- if (node == dummy) {
- level++;
- if (level == k) {
- return cnt;
- }
- cnt = 0; // reset the cnt;
- if (q.isEmpty()) {
- break;
- }
- q.offer(dummy);
- continue;
- }
- cnt++;
- if (node.left != null) {
- q.offer(node.left);
- }
- if (node.right != null) {
- q.offer(node.right);
- }
- }
- return 0;
- }
- /*
- * * 6. 求二叉树第K层的节点个数:getNodeNumKthLevelRec, getNodeNumKthLevel
- * */
- public static int getNodeNumKthLevelRec(TreeNode root, int k) {
- if (root == null || k <= 0) {
- return 0;
- }
- if (k == 1) {
- return 1;
- }
- // 将左子树及右子树在K层的节点个数相加.
- return getNodeNumKthLevelRec(root.left, k - 1) + getNodeNumKthLevelRec(root.right, k - 1);
- }
- /*
- * 7. getNodeNumLeafRec 把左子树和右子树的叶子节点加在一起即可
- * */
- public static int getNodeNumLeafRec(TreeNode root) {
- if (root == null) {
- return 0;
- }
- if (root.left == null && root.right == null) {
- return 1;
- }
- return getNodeNumLeafRec(root.left) + getNodeNumLeafRec(root.right);
- }
- /* 7. getNodeNumLeaf
- * 随便使用一种遍历方法都可以,比如,中序遍历。
- * inorderTraversal,判断是不是叶子节点。
- * */
- public static int getNodeNumLeaf(TreeNode root) {
- if (root == null) {
- return 0;
- }
- int cnt = 0;
- // we can use inorderTraversal travesal to do it.
- Stack<TreeNode> s = new Stack<TreeNode>();
- TreeNode cur = root;
- while (true) {
- while (cur != null) {
- s.push(cur);
- cur = cur.left;
- }
- if (s.isEmpty()) {
- break;
- }
- // all the left child has been put into the stack, let's deal with the
- // current node.
- cur = s.pop();
- if (cur.left == null && cur.right == null) {
- cnt++;
- }
- cur = cur.right;
- }
- return cnt;
- }
- /*
- * 8. 判断两棵二叉树是否相同的树。
- * 递归解法:
- * (1)如果两棵二叉树都为空,返回真
- * (2)如果两棵二叉树一棵为空,另一棵不为空,返回假
- * (3)如果两棵二叉树都不为空,如果对应的左子树和右子树都同构返回真,其他返回假
- * */
- public static boolean isSameRec(TreeNode r1, TreeNode r2) {
- // both are null.
- if (r1 == null && r2 == null) {
- return true;
- }
- // one is null.
- if (r1 == null || r2 == null) {
- return false;
- }
- // 1. the value of the root should be the same;
- // 2. the left tree should be the same.
- // 3. the right tree should be the same.
- return r1.val == r2.val &&
- isSameRec(r1.left, r2.left) && isSameRec(r1.right, r2.right);
- }
- /*
- * 8. 判断两棵二叉树是否相同的树。
- * 迭代解法
- * 我们直接用中序遍历来比较就好啦
- * */
- public static boolean isSame(TreeNode r1, TreeNode r2) {
- // both are null.
- if (r1 == null && r2 == null) {
- return true;
- }
- // one is null.
- if (r1 == null || r2 == null) {
- return false;
- }
- Stack<TreeNode> s1 = new Stack<TreeNode>();
- Stack<TreeNode> s2 = new Stack<TreeNode>();
- TreeNode cur1 = r1;
- TreeNode cur2 = r2;
- while (true) {
- while (cur1 != null && cur2 != null) {
- s1.push(cur1);
- s2.push(cur2);
- cur1 = cur1.left;
- cur2 = cur2.left;
- }
- if (cur1 != null || cur2 != null) {
- return false;
- }
- if (s1.isEmpty() && s2.isEmpty()) {
- break;
- }
- cur1 = s1.pop();
- cur2 = s2.pop();
- if (cur1.val != cur2.val) {
- return false;
- }
- cur1 = cur1.right;
- cur2 = cur2.right;
- }
- return true;
- }
- /*
- *
- * 9. 判断二叉树是不是平衡二叉树:isAVLRec
- * 1. 左子树,右子树的高度差不能超过1
- * 2. 左子树,右子树都是平衡二叉树。
- *
- */
- public static boolean isAVLRec(TreeNode root) {
- if (root == null) {
- return true;
- }
- // 左子树,右子树都必须是平衡二叉树。
- if (!isAVLRec(root.left) || !isAVLRec(root.right)) {
- return false;
- }
- int dif = Math.abs(getDepthRec(root.left) - getDepthRec(root.right));
- if (dif > 1) {
- return false;
- }
- return true;
- }
- /**
- * 10. 求二叉树的镜像 递归解法:
- *
- * (1) 破坏原来的树
- *
- * 1 1
- * / \
- * 2 -----> 2
- * \ /
- * 3 3
- * */
- public static TreeNode mirrorRec(TreeNode root) {
- if (root == null) {
- return null;
- }
- // 先把左右子树分别镜像,并且交换它们
- TreeNode tmp = root.right;
- root.right = mirrorRec(root.left);
- root.left = mirrorRec(tmp);
- return root;
- }
- /**
- * 10. 求二叉树的镜像 Iterator解法:
- *
- * (1) 破坏原来的树
- *
- * 1 1
- * / \
- * 2 -----> 2
- * \ /
- * 3 3
- *
- * 应该可以使用任何一种Traversal 方法。
- * 我们现在可以试看看使用最简单的前序遍历。
- * */
- public static TreeNode mirror(TreeNode root) {
- if (root == null) {
- return null;
- }
- Stack<TreeNode> s = new Stack<TreeNode>();
- s.push(root);
- while (!s.isEmpty()) {
- TreeNode cur = s.pop();
- // 交换当前节点的左右节点
- TreeNode tmp = cur.left;
- cur.left = cur.right;
- cur.right = tmp;
- // traversal 左节点,右节点。
- if (cur.right != null) {
- s.push(cur.right);
- }
- if (cur.left != null) {
- s.push(cur.left);
- }
- }
- return root;
- }
- /**
- * 10. 求二叉树的镜像 Iterator解法:
- *
- * (2) 创建一个新的树
- *
- * 1 1
- * / \
- * 2 -----> 2
- * \ /
- * 3 3
- *
- * 应该可以使用任何一种Traversal 方法。
- * 我们现在可以试看看使用最简单的前序遍历。
- * 前序遍历我们可以立刻把新建好的左右节点创建出来,比较方便
- * */
- public static TreeNode mirrorCopy(TreeNode root) {
- if (root == null) {
- return null;
- }
- Stack<TreeNode> s = new Stack<TreeNode>();
- Stack<TreeNode> sCopy = new Stack<TreeNode>();
- s.push(root);
- TreeNode rootCopy = new TreeNode(root.val);
- sCopy.push(rootCopy);
- while (!s.isEmpty()) {
- TreeNode cur = s.pop();
- TreeNode curCopy = sCopy.pop();
- // traversal 左节点,右节点。
- if (cur.right != null) {
- // copy 在这里做比较好,因为我们可以容易地找到它的父节点
- TreeNode leftCopy = new TreeNode(cur.right.val);
- curCopy.left = leftCopy;
- s.push(cur.right);
- sCopy.push(curCopy.left);
- }
- if (cur.left != null) {
- // copy 在这里做比较好,因为我们可以容易地找到它的父节点
- TreeNode rightCopy = new TreeNode(cur.left.val);
- curCopy.right = rightCopy;
- s.push(cur.left);
- sCopy.push(curCopy.right);
- }
- }
- return rootCopy;
- }
- /**
- * 10. 求二叉树的镜像 递归解法:
- *
- * (1) 不破坏原来的树,新建一个树
- *
- * 1 1
- * / \
- * 2 -----> 2
- * \ /
- * 3 3
- * */
- public static TreeNode mirrorCopyRec(TreeNode root) {
- if (root == null) {
- return null;
- }
- // 先把左右子树分别镜像,并且把它们连接到新建的root节点。
- TreeNode rootCopy = new TreeNode(root.val);
- rootCopy.left = mirrorCopyRec(root.right);
- rootCopy.right = mirrorCopyRec(root.left);
- return rootCopy;
- }
- /*
- * 10.1. 判断两个树是否互相镜像
- * (1) 根必须同时为空,或是同时不为空
- *
- * 如果根不为空:
- * (1).根的值一样
- * (2).r1的左树是r2的右树的镜像
- * (3).r1的右树是r2的左树的镜像
- * */
- public static boolean isMirrorRec(TreeNode r1, TreeNode r2){
- // 如果2个树都是空树
- if (r1 == null && r2 == null) {
- return true;
- }
- // 如果其中一个为空,则返回false.
- if (r1 == null || r2 == null) {
- return false;
- }
- // If both are not null, they should be:
- // 1. have same value for root.
- // 2. R1's left tree is the mirror of R2's right tree;
- // 3. R2's right tree is the mirror of R1's left tree;
- return r1.val == r2.val
- && isMirrorRec(r1.left, r2.right)
- && isMirrorRec(r1.right, r2.left);
- }
- /*
- * 10.1. 判断两个树是否互相镜像 Iterator 做法
- * (1) 根必须同时为空,或是同时不为空
- *
- * 如果根不为空:
- * traversal 整个树,判断它们是不是镜像,每次都按照反向来traversal
- * (1). 当前节点的值相等
- * (2). 当前节点的左右节点要镜像,
- * 无论是左节点,还是右节点,对应另外一棵树的镜像位置,可以同时为空,或是同时不为空,但是不可以一个为空,一个不为空。
- * */
- public static boolean isMirror(TreeNode r1, TreeNode r2){
- // 如果2个树都是空树
- if (r1 == null && r2 == null) {
- return true;
- }
- // 如果其中一个为空,则返回false.
- if (r1 == null || r2 == null) {
- return false;
- }
- Stack<TreeNode> s1 = new Stack<TreeNode>();
- Stack<TreeNode> s2 = new Stack<TreeNode>();
- s1.push(r1);
- s2.push(r2);
- while (!s1.isEmpty() && !s2.isEmpty()) {
- TreeNode cur1 = s1.pop();
- TreeNode cur2 = s2.pop();
- // 弹出的节点的值必须相等
- if (cur1.val != cur2.val) {
- return false;
- }
- // tree1的左节点,tree2的右节点,可以同时不为空,也可以同时为空,否则返回false.
- TreeNode left1 = cur1.left;
- TreeNode right1 = cur1.right;
- TreeNode left2 = cur2.left;
- TreeNode right2 = cur2.right;
- if (left1 != null && right2 != null) {
- s1.push(left1);
- s2.push(right2);
- } else if (!(left1 == null && right2 == null)) {
- return false;
- }
- // tree1的左节点,tree2的右节点,可以同时不为空,也可以同时为空,否则返回false.
- if (right1 != null && left2 != null) {
- s1.push(right1);
- s2.push(left2);
- } else if (!(right1 == null && left2 == null)) {
- return false;
- }
- }
- return true;
- }
- /*
- * 11. 求二叉树中两个节点的最低公共祖先节点:
- * Recursion Version:
- * LACRec
- * 1. If found in the left tree, return the Ancestor.
- * 2. If found in the right tree, return the Ancestor.
- * 3. If Didn't find any of the node, return null.
- * 4. If found both in the left and the right tree, return the root.
- * */
- public static TreeNode LACRec(TreeNode root, TreeNode node1, TreeNode node2) {
- if (root == null || node1 == null || node2 == null) {
- return null;
- }
- // If any of the node is the root, just return the root.
- if (root == node1 || root == node2) {
- return root;
- }
- // if no node is in the node, just recursively find it in LEFT and RIGHT tree.
- TreeNode left = LACRec(root.left, node1, node2);
- TreeNode right = LACRec(root.right, node1, node2);
- if (left == null) { // If didn't found in the left tree, then just return it from right.
- return right;
- } else if (right == null) { // Or if didn't found in the right tree, then just return it from the left side.
- return left;
- }
- // if both right and right found a node, just return the root as the Common Ancestor.
- return root;
- }
- /*
- * 11. 求BST中两个节点的最低公共祖先节点:
- * Recursive version:
- * LCABst
- *
- * 1. If found in the left tree, return the Ancestor.
- * 2. If found in the right tree, return the Ancestor.
- * 3. If Didn't find any of the node, return null.
- * 4. If found both in the left and the right tree, return the root.
- * */
- public static TreeNode LCABstRec(TreeNode root, TreeNode node1, TreeNode node2) {
- if (root == null || node1 == null || node2 == null) {
- return null;
- }
- // If any of the node is the root, just return the root.
- if (root == node1 || root == node2) {
- return root;
- }
- int min = Math.min(node1.val, node2.val);
- int max = Math.max(node1.val, node2.val);
- // if the values are smaller than the root value, just search them in the left tree.
- if (root.val > max) {
- return LCABstRec(root.left, node1, node2);
- } else if (root.val < min) {
- // if the values are larger than the root value, just search them in the right tree.
- return LCABstRec(root.right, node1, node2);
- }
- // if root is in the middle, just return the root.
- return root;
- }
- /*
- * 解法1. 记录下path,并且比较之:
- * LAC
- * http://www.geeksforgeeks.org/lowest-common-ancestor-binary-tree-set-1/
- * */
- public static TreeNode LCA(TreeNode root, TreeNode r1, TreeNode r2) {
- // If the nodes have one in the root, just return the root.
- if (root == null || r1 == null || r2 == null) {
- return null;
- }
- ArrayList<TreeNode> list1 = new ArrayList<TreeNode>();
- ArrayList<TreeNode> list2 = new ArrayList<TreeNode>();
- boolean find1 = LCAPath(root, r1, list1);
- boolean find2 = LCAPath(root, r2, list2);
- // If didn't find any of the node, just return a null.
- if (!find1 || !find2) {
- return null;
- }
- // 注意: 使用Iterator 对于linkedlist可以提高性能。
- // 所以 统一使用Iterator 来进行操作。
- Iterator<TreeNode> iter1 = list1.iterator();
- Iterator<TreeNode> iter2 = list2.iterator();
- TreeNode last = null;
- while (iter1.hasNext() && iter2.hasNext()) {
- TreeNode tmp1 = iter1.next();
- TreeNode tmp2 = iter2.next();
- if (tmp1 != tmp2) {
- return last;
- }
- last = tmp1;
- }
- // If never find any node which is different, means Node 1 and Node 2 are the same one.
- // so just return the last one.
- return last;
- }
- public static boolean LCAPath(TreeNode root, TreeNode node, ArrayList<TreeNode> path) {
- // if didn't find, we should return a empty path.
- if (root == null || node == null) {
- return false;
- }
- // First add the root node.
- path.add(root);
- // if the node is in the left side.
- if (root != node
- && !LCAPath(root.left, node, path)
- && !LCAPath(root.right, node, path)
- ) {
- // Didn't find the node. should remove the node added before.
- path.remove(root);
- return false;
- }
- // found
- return true;
- }
- /*
- * * 12. 求二叉树中节点的最大距离:getMaxDistanceRec
- *
- * 首先我们来定义这个距离:
- * 距离定义为:两个节点间边的数目.
- * 如:
- * 1
- * / \
- * 2 3
- * \
- * 4
- * 这里最大距离定义为2,4的距离,为3.
- * 求二叉树中节点的最大距离 即二叉树中相距最远的两个节点之间的距离。 (distance / diameter)
- * 递归解法:
- * 返回值设计:
- * 返回1. 深度, 2. 当前树的最长距离
- * (1) 计算左子树的深度,右子树深度,左子树独立的链条长度,右子树独立的链条长度
- * (2) 最大长度为三者之最:
- * a. 通过根节点的链,为左右深度+2
- * b. 左子树独立链
- * c. 右子树独立链。
- *
- * (3)递归初始条件:
- * 当root == null, depth = -1.maxDistance = -1;
- *
- */
- public static int getMaxDistanceRec(TreeNode root) {
- return getMaxDistanceRecHelp(root).maxDistance;
- }
- public static Result getMaxDistanceRecHelp(TreeNode root) {
- Result ret = new Result(-1, -1);
- if (root == null) {
- return ret;
- }
- Result left = getMaxDistanceRecHelp(root.left);
- Result right = getMaxDistanceRecHelp(root.right);
- // 深度应加1, the depth from the subtree to the root.
- ret.depth = Math.max(left.depth, right.depth) + 1;
- // 左子树,右子树与根的距离都要加1,所以通过根节点的路径为两边深度+2
- int crossLen = left.depth + right.depth + 2;
- // 求出cross根的路径,及左右子树的独立路径,这三者路径的最大值。
- ret.maxDistance = Math.max(left.maxDistance, right.maxDistance);
- ret.maxDistance = Math.max(ret.maxDistance, crossLen);
- return ret;
- }
- private static class Result {
- int depth;
- int maxDistance;
- public Result(int depth, int maxDistance) {
- this.depth = depth;
- this.maxDistance = maxDistance;
- }
- }
- /*
- * 13. 由前序遍历序列和中序遍历序列重建二叉树:rebuildBinaryTreeRec
- * We assume that there is no duplicate in the trees.
- * For example:
- * 1
- * / \
- * 2 3
- * /\ \
- * 4 5 6
- * /\
- * 7 8
- *
- * PreOrder should be: 1 2 4 5 3 6 7 8
- * 根 左子树 右子树
- * InOrder should be: 4 2 5 1 3 7 6 8
- * 左子树 根 右子树
- * */
- public static TreeNode rebuildBinaryTreeRec(List<Integer> preOrder, List<Integer> inOrder) {
- if (preOrder == null || inOrder == null) {
- return null;
- }
- // If the traversal is empty, just return a NULL.
- if (preOrder.size() == 0 || inOrder.size() == 0) {
- return null;
- }
- // we can get the root from the preOrder.
- // Because the first one is the root.
- // So we just create the root node here.
- TreeNode root = new TreeNode(preOrder.get(0));
- List<Integer> preOrderLeft;
- List<Integer> preOrderRight;
- List<Integer> inOrderLeft;
- List<Integer> inOrderRight;
- // 获得在 inOrder中,根的位置
- int rootInIndex = inOrder.indexOf(preOrder.get(0));
- preOrderLeft = preOrder.subList(1, rootInIndex + 1);
- preOrderRight = preOrder.subList(rootInIndex + 1, preOrder.size());
- // 得到inOrder左边的左子树
- inOrderLeft = inOrder.subList(0, rootInIndex);
- inOrderRight = inOrder.subList(rootInIndex + 1, inOrder.size());
- // 通过 Rec 来调用生成左右子树。
- root.left = rebuildBinaryTreeRec(preOrderLeft, inOrderLeft);
- root.right = rebuildBinaryTreeRec(preOrderRight, inOrderRight);
- return root;
- }
- /*
- * 14. 判断二叉树是不是完全二叉树:isCompleteBinaryTree, isCompleteBinaryTreeRec
- * 进行level traversal, 一旦遇到一个节点的左节点为空,后面的节点的子节点都必须为空。而且不应该有下一行,其实就是队列中所有的
- * 元素都不应该再有子元素。
- * */
- public static boolean isCompleteBinaryTree(TreeNode root) {
- if (root == null) {
- return false;
- }
- TreeNode dummyNode = new TreeNode(0);
- Queue<TreeNode> q = new LinkedList<TreeNode>();
- q.offer(root);
- q.offer(dummyNode);
- // if this is true, no node should have any child.
- boolean noChild = false;
- while (!q.isEmpty()) {
- TreeNode cur = q.poll();
- if (cur == dummyNode) {
- if (!q.isEmpty()) {
- q.offer(dummyNode);
- }
- // Dummy node不需要处理。
- continue;
- }
- if (cur.left != null) {
- // 如果标记被设置,则Queue中任何元素不应再有子元素。
- if (noChild) {
- return false;
- }
- q.offer(cur.left);
- } else {
- // 一旦某元素没有左节点或是右节点,则之后所有的元素都不应有子元素。
- // 并且该元素不可以有右节点.
- noChild = true;
- }
- if (cur.right != null) {
- // 如果标记被设置,则Queue中任何元素不应再有子元素。
- if (noChild) {
- return false;
- }
- q.offer(cur.right);
- } else {
- // 一旦某元素没有左节点或是右节点,则之后所有的元素都不应有子元素。
- noChild = true;
- }
- }
- return true;
- }
- /*
- * 14. 判断二叉树是不是完全二叉树:isCompleteBinaryTreeRec
- *
- *
- * 我们可以分解为:
- * CompleteBinary Tree 的条件是:
- * 1. 左右子树均为Perfect binary tree, 并且两者Height相同
- * 2. 左子树为CompleteBinaryTree, 右子树为Perfect binary tree,并且两者Height差1
- * 3. 左子树为Perfect Binary Tree,右子树为CompleteBinaryTree, 并且Height 相同
- *
- * Base 条件:
- * (1) root = null: 为perfect & complete BinaryTree, Height -1;
- *
- * 而 Perfect Binary Tree的条件:
- * 左右子树均为Perfect Binary Tree,并且Height 相同。
- * */
- public static boolean isCompleteBinaryTreeRec(TreeNode root) {
- return isCompleteBinaryTreeRecHelp(root).isCompleteBT;
- }
- private static class ReturnBinaryTree {
- boolean isCompleteBT;
- boolean isPerfectBT;
- int height;
- ReturnBinaryTree(boolean isCompleteBT, boolean isPerfectBT, int height) {
- this.isCompleteBT = isCompleteBT;
- this.isPerfectBT = isPerfectBT;
- this.height = height;
- }
- }
- /*
- * 我们可以分解为:
- * CompleteBinary Tree 的条件是:
- * 1. 左右子树均为Perfect binary tree, 并且两者Height相同
- * 2. 左子树为CompleteBinaryTree, 右子树为Perfect binary tree,并且两者Height差1
- * 3. 左子树为Perfect Binary Tree,右子树为CompleteBinaryTree, 并且Height 相同
- *
- * Base 条件:
- * (1) root = null: 为perfect & complete BinaryTree, Height -1;
- *
- * 而 Perfect Binary Tree的条件:
- * 左右子树均为Perfect Binary Tree,并且Height 相同。
- * */
- public static ReturnBinaryTree isCompleteBinaryTreeRecHelp(TreeNode root) {
- ReturnBinaryTree ret = new ReturnBinaryTree(true, true, -1);
- if (root == null) {
- return ret;
- }
- ReturnBinaryTree left = isCompleteBinaryTreeRecHelp(root.left);
- ReturnBinaryTree right = isCompleteBinaryTreeRecHelp(root.right);
- // 树的高度为左树高度,右树高度的最大值+1
- ret.height = 1 + Math.max(left.height, right.height);
- // set the isPerfectBT
- ret.isPerfectBT = false;
- if (left.isPerfectBT && right.isPerfectBT && left.height == right.height) {
- ret.isPerfectBT = true;
- }
- // set the isCompleteBT.
- /*
- * CompleteBinary Tree 的条件是:
- * 1. 左右子树均为Perfect binary tree, 并且两者Height相同(其实就是本树是perfect tree)
- * 2. 左子树为CompleteBinaryTree, 右子树为Perfect binary tree,并且两者Height差1
- * 3. 左子树为Perfect Binary Tree,右子树为CompleteBinaryTree, 并且Height 相同
- * */
- ret.isCompleteBT = ret.isPerfectBT
- || (left.isCompleteBT && right.isPerfectBT && left.height == right.height + 1)
- || (left.isPerfectBT && right.isCompleteBT && left.height == right.height);
- return ret;
- }
- /*
- * 15. findLongest
- * 第一种解法:
- * 返回左边最长,右边最长,及左子树最长,右子树最长。
- * */
- public static int findLongest(TreeNode root) {
- if (root == null) {
- return -1;
- }
- TreeNode l = root;
- int cntL = 0;
- while (l.left != null) {
- cntL++;
- l = l.left;
- }
- TreeNode r = root;
- int cntR = 0;
- while (r.right != null) {
- cntR++;
- r = r.right;
- }
- int lmax = findLongest(root.left);
- int rmax = findLongest(root.right);
- int max = Math.max(lmax, rmax);
- max = Math.max(max, cntR);
- max = Math.max(max, cntL);
- return max;
- }
- /* 1
- * 2 3
- * 3 4
- * 6 1
- * 7
- * 9
- * 11
- * 2
- * 14
- * */
- public static int findLongest2(TreeNode root) {
- int [] maxVal = new int[1];
- maxVal[0] = -1;
- findLongest2Help(root, maxVal);
- return maxVal[0];
- }
- // ret:
- // 0: the left side longest,
- // 1: the right side longest.
- static int maxLen = -1;
- static int[] findLongest2Help(TreeNode root, int[] maxVal) {
- int[] ret = new int[2];
- if (root == null) {
- ret[0] = -1;
- ret[1] = -1;
- return ret;
- }
- ret[0] = findLongest2Help(root.left, maxVal)[0] + 1;
- ret[1] = findLongest2Help(root.right, maxVal)[1] + 1;
- //maxLen = Math.max(maxLen, ret[0]);
- //maxLen = Math.max(maxLen, ret[1]);
- maxVal[0] = Math.max(maxVal[0], ret[0]);
- maxVal[0] = Math.max(maxVal[0], ret[1]);
- return ret;
- }
- }
package Algorithms.tree;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Stack;
/**
* REFS:
* http://blog.csdn.net/fightforyourdream/article/details/16843303 面试大总结之二:Java搞定面试中的二叉树题目
* http://blog.csdn.net/luckyxiaoqiang/article/details/7518888 轻松搞定面试中的二叉树题目
* http://www.cnblogs.com/Jax/archive/2009/12/28/1633691.html 算法大全(3) 二叉树
*
* 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
* mirror, mirrorCopy
* 10.1 判断两个树是否互相镜像:isMirrorRec isMirror
* 11. 求二叉树中两个节点的最低公共祖先节点:
* LAC 求解最小公共祖先, 使用list来存储path.
* LCABstRec 递归求解BST树.
* LCARec 递归算法 .
* 12. 求二叉树中节点的最大距离:getMaxDistanceRec
* 13. 由前序遍历序列和中序遍历序列重建二叉树:rebuildBinaryTreeRec
* 14. 判断二叉树是不是完全二叉树:isCompleteBinaryTree, isCompleteBinaryTreeRec
* 15. 找出二叉树中最长连续子串(即全部往左的连续节点,或是全部往右的连续节点)findLongest
*/
public class TreeDemo {
/*
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);
/*
10
/ \
6 14
/ \ \
4 8 16
/
0
*/
/*
1
/ \
2 3
/ \ \
4 5 6
*/
// TreeNode r1 = new TreeNode(10);
// TreeNode r2 = new TreeNode(6);
// TreeNode r3 = new TreeNode(14);
// TreeNode r4 = new TreeNode(4);
// TreeNode r5 = new TreeNode(8);
// TreeNode r6 = new TreeNode(16);
TreeNode r7 = new TreeNode(0);
r1.left = r2;
r1.right = r3;
r2.left = r4;
r2.right = r5;
r3.right = r6;
r4.left = r7;
TreeNode t1 = new TreeNode(10);
TreeNode t2 = new TreeNode(6);
TreeNode t3 = new TreeNode(14);
TreeNode t4 = new TreeNode(4);
TreeNode t5 = new TreeNode(8);
TreeNode t6 = new TreeNode(16);
TreeNode t7 = new TreeNode(0);
TreeNode t8 = new TreeNode(0);
TreeNode t9 = new TreeNode(0);
TreeNode t10 = new TreeNode(0);
TreeNode t11 = new TreeNode(0);
t1.left = t2;
t1.right = t3;
t2.left = t4;
t2.right = t5;
t3.left = t6;
t3.right = t7;
t4.left = t8;
//t4.right = t9;
t5.right = t9;
// test distance
// t5.right = t8;
// t8.right = t9;
// t9.right = t10;
// t10.right = t11;
/*
10
/ \
6 14
/ \ \
4 8 16
/
0
*/
// System.out.println(LCABstRec(t1, t2, t4).val);
// System.out.println(LCABstRec(t1, t2, t6).val);
// System.out.println(LCABstRec(t1, t4, t6).val);
// System.out.println(LCABstRec(t1, t4, t7).val);
// System.out.println(LCABstRec(t1, t3, t6).val);
//
// System.out.println(LCA(t1, t2, t4).val);
// System.out.println(LCA(t1, t2, t6).val);
// System.out.println(LCA(t1, t4, t6).val);
// System.out.println(LCA(t1, t4, t7).val);
// System.out.println(LCA(t1, t3, t6).val);
// System.out.println(LCA(t1, t6, t6).val);
//System.out.println(getMaxDistanceRec(t1));
//System.out.println(isSame(r1, t1));
// System.out.println(isAVLRec(r1));
//
// preorderTraversalRec(r1);
// //mirrorRec(r1);
// //TreeNode r1Mirror = mirror(r1);
//
// TreeNode r1MirrorCopy = mirrorCopy(r1);
// System.out.println();
// //preorderTraversalRec(r1Mirror);
// preorderTraversalRec(r1MirrorCopy);
//
// System.out.println();
//
// System.out.println(isMirrorRec(r1, r1MirrorCopy));
// System.out.println(isMirror(r1, r1MirrorCopy));
//System.out.println(getNodeNumKthLevelRec(r1, 5));
//System.out.println(getNodeNumLeaf(r1));
// System.out.println(getNodeNumRec(null));
// System.out.println(getNodeNum(r1));
//System.out.println(getDepthRec(null));
// System.out.println(getDepth(r1));
//
// preorderTraversalRec(r1);
// System.out.println();
// preorderTraversal(r1);
// System.out.println();
// inorderTraversalRec(r1);
//
// System.out.println();
// inorderTraversal(r1);
// postorderTraversalRec(r1);
// System.out.println();
// postorderTraversal(r1);
// System.out.println();
// levelTraversal(r1);
//
// System.out.println();
// levelTraversalRec(r1);
// TreeNode ret = convertBST2DLLRec(r1);
// while (ret != null) {
// System.out.print(ret.val + " ");
// ret = ret.right;
// }
// TreeNode ret2 = convertBST2DLL(r1);
// while (ret2.right != null) {
// ret2 = ret2.right;
// }
//
// while (ret2 != null) {
// System.out.print(ret2.val + " ");
// ret2 = ret2.left;
// }
//
// TreeNode ret = convertBST2DLL(r1);
// while (ret != null) {
// System.out.print(ret.val + " ");
// ret = ret.right;
// }
// System.out.println();
// System.out.println(findLongest(r1));
// System.out.println();
// System.out.println(findLongest2(r1));
// test the rebuildBinaryTreeRec.
//test_rebuildBinaryTreeRec();
System.out.println(isCompleteBinaryTreeRec(t1));
System.out.println(isCompleteBinaryTree(t1));
}
public static void test_rebuildBinaryTreeRec() {
ArrayList<Integer> list1 = new ArrayList<Integer>();
list1.add(1);
list1.add(2);
list1.add(4);
list1.add(5);
list1.add(3);
list1.add(6);
list1.add(7);
list1.add(8);
ArrayList<Integer> list2 = new ArrayList<Integer>();
list2.add(4);
list2.add(2);
list2.add(5);
list2.add(1);
list2.add(3);
list2.add(7);
list2.add(6);
list2.add(8);
TreeNode root = rebuildBinaryTreeRec(list1, list2);
preorderTraversalRec(root);
System.out.println();
postorderTraversalRec(root);
}
private static class TreeNode{
int val;
TreeNode left;
TreeNode right;
public TreeNode(int val){
this.val = val;
left = null;
right = null;
}
}
/*
* null返回0,然后把左右子树的size加上即可。
* */
public static int getNodeNumRec(TreeNode root) {
if (root == null) {
return 0;
}
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;
}
Queue<TreeNode> q = new LinkedList<TreeNode>();
q.offer(root);
int cnt = 0;
while (!q.isEmpty()) {
TreeNode node = q.poll();
if (node.left != null) {
q.offer(node.left);
}
if (node.right != null) {
q.offer(node.right);
}
cnt++;
}
return cnt;
}
public static int getDepthRec(TreeNode root) {
if (root == null) {
return -1;
}
return Math.max(getDepthRec(root.left), getDepthRec(root.right)) + 1;
}
/*
* 可以用 level LevelOrderTraversal 来实现,我们用一个dummyNode来分隔不同的层,这样即可计算出实际的depth.
* 1
/ \
2 3
/ \ \
4 5 6
*
* 在队列中如此排列: 1, dummy, 2, 3, dummy, 4, 5, 5, dummy
*
*/
public static int getDepth(TreeNode root) {
if (root == null) {
return 0;
}
TreeNode dummy = new TreeNode(0);
Queue<TreeNode> q = new LinkedList<TreeNode>();
q.offer(root);
q.offer(dummy);
int depth = -1;
while (!q.isEmpty()) {
TreeNode curr = q.poll();
if (curr == dummy) {
depth++;
if (!q.isEmpty()) { // 使用DummyNode来区分不同的层, 如果下一层不是为空,则应该在尾部加DummyNode.
q.offer(dummy);
}
}
if (curr.left != null) {
q.offer(curr.left);
}
if (curr.right != null) {
q.offer(curr.right);
}
}
return depth;
}
/*
* 3. 前序遍历,中序遍历,后序遍历: preorderTraversalRec, preorderTraversal, inorderTraversalRec, postorderTraversalRec
* (https://en.wikipedia.org/wiki/Tree_traversal#Pre-order_2)
* */
public static void preorderTraversalRec(TreeNode root) {
if (root == null) {
return;
}
System.out.print(root.val + " ");
preorderTraversalRec(root.left);
preorderTraversalRec(root.right);
}
/*
* 前序遍历,Iteration 算法. 把根节点存在stack中。
* */
public static void preorderTraversal(TreeNode root) {
if (root == null) {
return;
}
Stack<TreeNode> s = new Stack<TreeNode>();
s.push(root);
while (!s.isEmpty()) {
TreeNode node = s.pop();
System.out.print(node.val + " ");
if (node.right != null) { //
s.push(node.right);
}
// 我们需要先压入右节点,再压入左节点,这样就可以先弹出左节点。
if (node.left != null) {
s.push(node.left);
}
}
}
/*
* 中序遍历
* */
public static void inorderTraversalRec(TreeNode root) {
if (root == null) {
return;
}
inorderTraversalRec(root.left);
System.out.print(root.val + " ");
inorderTraversalRec(root.right);
}
/**
* 中序遍历迭代解法 ,用栈先把根节点的所有左孩子都添加到栈内,
* 然后输出栈顶元素,再处理栈顶元素的右子树
* http://www.youtube.com/watch?v=50v1sJkjxoc
*
* 还有一种方法能不用递归和栈,基于线索二叉树的方法,较麻烦以后补上
* http://www.geeksforgeeks.org/inorder-tree-traversal-without-recursion-and-without-stack/
*/
public static void inorderTraversal(TreeNode root) {
if (root == null) {
return;
}
Stack<TreeNode> s = new Stack<TreeNode>();
TreeNode cur = root;
while(true) {
// 把当前节点的左节点都push到栈中.
while (cur != null) {
s.push(cur);
cur = cur.left;
}
if (s.isEmpty()) {
break;
}
// 因为此时已经没有左孩子了,所以输出栈顶元素
cur = s.pop();
System.out.print(cur.val + " ");
// 准备处理右子树
cur = cur.right;
}
}
// 后序遍历
/*
* 1
/ \
2 3
/ \ \
4 5 6
if put into the stack directly, then it should be:
1, 2, 4, 5, 3, 6 in the stack.
when pop, it should be: 6, 3, 5, 4, 2, 1
if I
* */
public static void postorderTraversalRec(TreeNode root) {
if (root == null) {
return;
}
postorderTraversalRec(root.left);
postorderTraversalRec(root.right);
System.out.print(root.val + " ");
}
/**
* 后序遍历迭代解法
* http://www.youtube.com/watch?v=hv-mJUs5mvU
* http://blog.csdn.net/tang_jin2015/article/details/8545457
* 从左到右的后序 与从右到左的前序的逆序是一样的,所以就简单喽! 哈哈
* 用另外一个栈进行翻转即可喽
*/
public static void postorderTraversal(TreeNode root) {
if (root == null) {
return;
}
Stack<TreeNode> s = new Stack<TreeNode>();
Stack<TreeNode> out = new Stack<TreeNode>();
s.push(root);
while(!s.isEmpty()) {
TreeNode cur = s.pop();
out.push(cur);
if (cur.left != null) {
s.push(cur.left);
}
if (cur.right != null) {
s.push(cur.right);
}
}
while(!out.isEmpty()) {
System.out.print(out.pop().val + " ");
}
}
/*
* 分层遍历二叉树(按层次从上往下,从左往右)迭代
* 其实就是广度优先搜索,使用队列实现。队列初始化,将根节点压入队列。当队列不为空,进行如下操作:弹出一个节点
* ,访问,若左子节点或右子节点不为空,将其压入队列
* */
public static void levelTraversal(TreeNode root) {
if (root == null) {
return;
}
Queue<TreeNode> q = new LinkedList<TreeNode>();
q.offer(root);
while (!q.isEmpty()) {
TreeNode cur = q.poll();
System.out.print(cur.val + " ");
if (cur.left != null) {
q.offer(cur.left);
}
if (cur.right != null) {
q.offer(cur.right);
}
}
}
public static void levelTraversalRec(TreeNode root) {
ArrayList<ArrayList<Integer>> ret = new ArrayList<ArrayList<Integer>>();
levelTraversalVisit(root, 0, ret);
System.out.println(ret);
}
/**
* 分层遍历二叉树(递归)
* 很少有人会用递归去做level traversal
* 基本思想是用一个大的ArrayList,里面包含了每一层的ArrayList。
* 大的ArrayList的size和level有关系
*
* http://discuss.leetcode.com/questions/49/binary-tree-level-order-traversal#answer-container-2543
*/
public static void levelTraversalVisit(TreeNode root, int level, ArrayList<ArrayList<Integer>> ret) {
if (root == null) {
return;
}
// 如果ArrayList的层数不够用, 则新添加一层
// when size = 3, level: 0, 1, 2
if (level >= ret.size()) {
ret.add(new ArrayList<Integer>());
}
// visit 当前节点
ret.get(level).add(root.val);
// 将左子树, 右子树添加到对应的层。
levelTraversalVisit(root.left, level + 1, ret);
levelTraversalVisit(root.right, level + 1, ret);
}
/*
* 题目要求:将二叉查找树转换成排序的双向链表,不能创建新节点,只调整指针。
查找树的结点定义如下:
既然是树,其定义本身就是递归的,自然用递归算法处理就很容易。将根结点的左子树和右子树转换为有序的双向链表,
然后根节点的left指针指向左子树结果的最后一个结点,同时左子树最后一个结点的right指针指向根节点;
根节点的right指针指向右子树结果的第一个结点,
同时右子树第一个结点的left指针指向根节点。
* */
public static TreeNode convertBST2DLLRec(TreeNode root) {
return convertBST2DLLRecHelp(root)[0];
}
/*
* ret[0] 代表左指针
* ret[1] 代表右指针
* */
public static TreeNode[] convertBST2DLLRecHelp(TreeNode root) {
TreeNode[] ret = new TreeNode[2];
ret[0] = null;
ret[1] = null;
if (root == null) {
return ret;
}
if (root.left != null) {
TreeNode left[] = convertBST2DLLRecHelp(root.left);
left[1].right = root; // 将左子树的尾节点连接到根
root.left = left[1];
ret[0] = left[0];
} else {
ret[0] = root; // 左节点返回root.
}
if (root.right != null) {
TreeNode right[] = convertBST2DLLRecHelp(root.right);
right[0].left = root; // 将右子树的头节点连接到根
root.right = right[0];
ret[1] = right[1];
} else {
ret[1] = root; // 右节点返回root.
}
return ret;
}
/**
* 将二叉查找树变为有序的双向链表 迭代解法
* 类似inOrder traversal的做法
*/
public static TreeNode convertBST2DLL(TreeNode root) {
while (root == null) {
return null;
}
TreeNode pre = null;
Stack<TreeNode> s = new Stack<TreeNode>();
TreeNode cur = root;
TreeNode head = null; // 链表头
while (true) {
while (cur != null) {
s.push(cur);
cur = cur.left;
}
// if stack is empty, just break;
if (s.isEmpty()) {
break;
}
cur = s.pop();
if (head == null) {
head = cur;
}
// link pre and cur.
cur.left = pre;
if (pre != null) {
pre.right = cur;
}
// 左节点已经处理完了,处理右节点
cur = cur.right;
pre = cur;
}
return root;
}
/*
* * 6. 求二叉树第K层的节点个数:getNodeNumKthLevelRec, getNodeNumKthLevel
* */
public static int getNodeNumKthLevel(TreeNode root, int k) {
if (root == null || k <= 0) {
return 0;
}
int level = 0;
Queue<TreeNode> q = new LinkedList<TreeNode>();
q.offer(root);
TreeNode dummy = new TreeNode(0);
int cnt = 0; // record the size of the level.
q.offer(dummy);
while (!q.isEmpty()) {
TreeNode node = q.poll();
if (node == dummy) {
level++;
if (level == k) {
return cnt;
}
cnt = 0; // reset the cnt;
if (q.isEmpty()) {
break;
}
q.offer(dummy);
continue;
}
cnt++;
if (node.left != null) {
q.offer(node.left);
}
if (node.right != null) {
q.offer(node.right);
}
}
return 0;
}
/*
* * 6. 求二叉树第K层的节点个数:getNodeNumKthLevelRec, getNodeNumKthLevel
* */
public static int getNodeNumKthLevelRec(TreeNode root, int k) {
if (root == null || k <= 0) {
return 0;
}
if (k == 1) {
return 1;
}
// 将左子树及右子树在K层的节点个数相加.
return getNodeNumKthLevelRec(root.left, k - 1) + getNodeNumKthLevelRec(root.right, k - 1);
}
/*
* 7. getNodeNumLeafRec 把左子树和右子树的叶子节点加在一起即可
* */
public static int getNodeNumLeafRec(TreeNode root) {
if (root == null) {
return 0;
}
if (root.left == null && root.right == null) {
return 1;
}
return getNodeNumLeafRec(root.left) + getNodeNumLeafRec(root.right);
}
/* 7. getNodeNumLeaf
* 随便使用一种遍历方法都可以,比如,中序遍历。
* inorderTraversal,判断是不是叶子节点。
* */
public static int getNodeNumLeaf(TreeNode root) {
if (root == null) {
return 0;
}
int cnt = 0;
// we can use inorderTraversal travesal to do it.
Stack<TreeNode> s = new Stack<TreeNode>();
TreeNode cur = root;
while (true) {
while (cur != null) {
s.push(cur);
cur = cur.left;
}
if (s.isEmpty()) {
break;
}
// all the left child has been put into the stack, let's deal with the
// current node.
cur = s.pop();
if (cur.left == null && cur.right == null) {
cnt++;
}
cur = cur.right;
}
return cnt;
}
/*
* 8. 判断两棵二叉树是否相同的树。
* 递归解法:
* (1)如果两棵二叉树都为空,返回真
* (2)如果两棵二叉树一棵为空,另一棵不为空,返回假
* (3)如果两棵二叉树都不为空,如果对应的左子树和右子树都同构返回真,其他返回假
* */
public static boolean isSameRec(TreeNode r1, TreeNode r2) {
// both are null.
if (r1 == null && r2 == null) {
return true;
}
// one is null.
if (r1 == null || r2 == null) {
return false;
}
// 1. the value of the root should be the same;
// 2. the left tree should be the same.
// 3. the right tree should be the same.
return r1.val == r2.val &&
isSameRec(r1.left, r2.left) && isSameRec(r1.right, r2.right);
}
/*
* 8. 判断两棵二叉树是否相同的树。
* 迭代解法
* 我们直接用中序遍历来比较就好啦
* */
public static boolean isSame(TreeNode r1, TreeNode r2) {
// both are null.
if (r1 == null && r2 == null) {
return true;
}
// one is null.
if (r1 == null || r2 == null) {
return false;
}
Stack<TreeNode> s1 = new Stack<TreeNode>();
Stack<TreeNode> s2 = new Stack<TreeNode>();
TreeNode cur1 = r1;
TreeNode cur2 = r2;
while (true) {
while (cur1 != null && cur2 != null) {
s1.push(cur1);
s2.push(cur2);
cur1 = cur1.left;
cur2 = cur2.left;
}
if (cur1 != null || cur2 != null) {
return false;
}
if (s1.isEmpty() && s2.isEmpty()) {
break;
}
cur1 = s1.pop();
cur2 = s2.pop();
if (cur1.val != cur2.val) {
return false;
}
cur1 = cur1.right;
cur2 = cur2.right;
}
return true;
}
/*
*
* 9. 判断二叉树是不是平衡二叉树:isAVLRec
* 1. 左子树,右子树的高度差不能超过1
* 2. 左子树,右子树都是平衡二叉树。
*
*/
public static boolean isAVLRec(TreeNode root) {
if (root == null) {
return true;
}
// 左子树,右子树都必须是平衡二叉树。
if (!isAVLRec(root.left) || !isAVLRec(root.right)) {
return false;
}
int dif = Math.abs(getDepthRec(root.left) - getDepthRec(root.right));
if (dif > 1) {
return false;
}
return true;
}
/**
* 10. 求二叉树的镜像 递归解法:
*
* (1) 破坏原来的树
*
* 1 1
* / \
* 2 -----> 2
* \ /
* 3 3
* */
public static TreeNode mirrorRec(TreeNode root) {
if (root == null) {
return null;
}
// 先把左右子树分别镜像,并且交换它们
TreeNode tmp = root.right;
root.right = mirrorRec(root.left);
root.left = mirrorRec(tmp);
return root;
}
/**
* 10. 求二叉树的镜像 Iterator解法:
*
* (1) 破坏原来的树
*
* 1 1
* / \
* 2 -----> 2
* \ /
* 3 3
*
* 应该可以使用任何一种Traversal 方法。
* 我们现在可以试看看使用最简单的前序遍历。
* */
public static TreeNode mirror(TreeNode root) {
if (root == null) {
return null;
}
Stack<TreeNode> s = new Stack<TreeNode>();
s.push(root);
while (!s.isEmpty()) {
TreeNode cur = s.pop();
// 交换当前节点的左右节点
TreeNode tmp = cur.left;
cur.left = cur.right;
cur.right = tmp;
// traversal 左节点,右节点。
if (cur.right != null) {
s.push(cur.right);
}
if (cur.left != null) {
s.push(cur.left);
}
}
return root;
}
/**
* 10. 求二叉树的镜像 Iterator解法:
*
* (2) 创建一个新的树
*
* 1 1
* / \
* 2 -----> 2
* \ /
* 3 3
*
* 应该可以使用任何一种Traversal 方法。
* 我们现在可以试看看使用最简单的前序遍历。
* 前序遍历我们可以立刻把新建好的左右节点创建出来,比较方便
* */
public static TreeNode mirrorCopy(TreeNode root) {
if (root == null) {
return null;
}
Stack<TreeNode> s = new Stack<TreeNode>();
Stack<TreeNode> sCopy = new Stack<TreeNode>();
s.push(root);
TreeNode rootCopy = new TreeNode(root.val);
sCopy.push(rootCopy);
while (!s.isEmpty()) {
TreeNode cur = s.pop();
TreeNode curCopy = sCopy.pop();
// traversal 左节点,右节点。
if (cur.right != null) {
// copy 在这里做比较好,因为我们可以容易地找到它的父节点
TreeNode leftCopy = new TreeNode(cur.right.val);
curCopy.left = leftCopy;
s.push(cur.right);
sCopy.push(curCopy.left);
}
if (cur.left != null) {
// copy 在这里做比较好,因为我们可以容易地找到它的父节点
TreeNode rightCopy = new TreeNode(cur.left.val);
curCopy.right = rightCopy;
s.push(cur.left);
sCopy.push(curCopy.right);
}
}
return rootCopy;
}
/**
* 10. 求二叉树的镜像 递归解法:
*
* (1) 不破坏原来的树,新建一个树
*
* 1 1
* / \
* 2 -----> 2
* \ /
* 3 3
* */
public static TreeNode mirrorCopyRec(TreeNode root) {
if (root == null) {
return null;
}
// 先把左右子树分别镜像,并且把它们连接到新建的root节点。
TreeNode rootCopy = new TreeNode(root.val);
rootCopy.left = mirrorCopyRec(root.right);
rootCopy.right = mirrorCopyRec(root.left);
return rootCopy;
}
/*
* 10.1. 判断两个树是否互相镜像
* (1) 根必须同时为空,或是同时不为空
*
* 如果根不为空:
* (1).根的值一样
* (2).r1的左树是r2的右树的镜像
* (3).r1的右树是r2的左树的镜像
* */
public static boolean isMirrorRec(TreeNode r1, TreeNode r2){
// 如果2个树都是空树
if (r1 == null && r2 == null) {
return true;
}
// 如果其中一个为空,则返回false.
if (r1 == null || r2 == null) {
return false;
}
// If both are not null, they should be:
// 1. have same value for root.
// 2. R1's left tree is the mirror of R2's right tree;
// 3. R2's right tree is the mirror of R1's left tree;
return r1.val == r2.val
&& isMirrorRec(r1.left, r2.right)
&& isMirrorRec(r1.right, r2.left);
}
/*
* 10.1. 判断两个树是否互相镜像 Iterator 做法
* (1) 根必须同时为空,或是同时不为空
*
* 如果根不为空:
* traversal 整个树,判断它们是不是镜像,每次都按照反向来traversal
* (1). 当前节点的值相等
* (2). 当前节点的左右节点要镜像,
* 无论是左节点,还是右节点,对应另外一棵树的镜像位置,可以同时为空,或是同时不为空,但是不可以一个为空,一个不为空。
* */
public static boolean isMirror(TreeNode r1, TreeNode r2){
// 如果2个树都是空树
if (r1 == null && r2 == null) {
return true;
}
// 如果其中一个为空,则返回false.
if (r1 == null || r2 == null) {
return false;
}
Stack<TreeNode> s1 = new Stack<TreeNode>();
Stack<TreeNode> s2 = new Stack<TreeNode>();
s1.push(r1);
s2.push(r2);
while (!s1.isEmpty() && !s2.isEmpty()) {
TreeNode cur1 = s1.pop();
TreeNode cur2 = s2.pop();
// 弹出的节点的值必须相等
if (cur1.val != cur2.val) {
return false;
}
// tree1的左节点,tree2的右节点,可以同时不为空,也可以同时为空,否则返回false.
TreeNode left1 = cur1.left;
TreeNode right1 = cur1.right;
TreeNode left2 = cur2.left;
TreeNode right2 = cur2.right;
if (left1 != null && right2 != null) {
s1.push(left1);
s2.push(right2);
} else if (!(left1 == null && right2 == null)) {
return false;
}
// tree1的左节点,tree2的右节点,可以同时不为空,也可以同时为空,否则返回false.
if (right1 != null && left2 != null) {
s1.push(right1);
s2.push(left2);
} else if (!(right1 == null && left2 == null)) {
return false;
}
}
return true;
}
/*
* 11. 求二叉树中两个节点的最低公共祖先节点:
* Recursion Version:
* LACRec
* 1. If found in the left tree, return the Ancestor.
* 2. If found in the right tree, return the Ancestor.
* 3. If Didn't find any of the node, return null.
* 4. If found both in the left and the right tree, return the root.
* */
public static TreeNode LACRec(TreeNode root, TreeNode node1, TreeNode node2) {
if (root == null || node1 == null || node2 == null) {
return null;
}
// If any of the node is the root, just return the root.
if (root == node1 || root == node2) {
return root;
}
// if no node is in the node, just recursively find it in LEFT and RIGHT tree.
TreeNode left = LACRec(root.left, node1, node2);
TreeNode right = LACRec(root.right, node1, node2);
if (left == null) { // If didn't found in the left tree, then just return it from right.
return right;
} else if (right == null) { // Or if didn't found in the right tree, then just return it from the left side.
return left;
}
// if both right and right found a node, just return the root as the Common Ancestor.
return root;
}
/*
* 11. 求BST中两个节点的最低公共祖先节点:
* Recursive version:
* LCABst
*
* 1. If found in the left tree, return the Ancestor.
* 2. If found in the right tree, return the Ancestor.
* 3. If Didn't find any of the node, return null.
* 4. If found both in the left and the right tree, return the root.
* */
public static TreeNode LCABstRec(TreeNode root, TreeNode node1, TreeNode node2) {
if (root == null || node1 == null || node2 == null) {
return null;
}
// If any of the node is the root, just return the root.
if (root == node1 || root == node2) {
return root;
}
int min = Math.min(node1.val, node2.val);
int max = Math.max(node1.val, node2.val);
// if the values are smaller than the root value, just search them in the left tree.
if (root.val > max) {
return LCABstRec(root.left, node1, node2);
} else if (root.val < min) {
// if the values are larger than the root value, just search them in the right tree.
return LCABstRec(root.right, node1, node2);
}
// if root is in the middle, just return the root.
return root;
}
/*
* 解法1. 记录下path,并且比较之:
* LAC
* http://www.geeksforgeeks.org/lowest-common-ancestor-binary-tree-set-1/
* */
public static TreeNode LCA(TreeNode root, TreeNode r1, TreeNode r2) {
// If the nodes have one in the root, just return the root.
if (root == null || r1 == null || r2 == null) {
return null;
}
ArrayList<TreeNode> list1 = new ArrayList<TreeNode>();
ArrayList<TreeNode> list2 = new ArrayList<TreeNode>();
boolean find1 = LCAPath(root, r1, list1);
boolean find2 = LCAPath(root, r2, list2);
// If didn't find any of the node, just return a null.
if (!find1 || !find2) {
return null;
}
// 注意: 使用Iterator 对于linkedlist可以提高性能。
// 所以 统一使用Iterator 来进行操作。
Iterator<TreeNode> iter1 = list1.iterator();
Iterator<TreeNode> iter2 = list2.iterator();
TreeNode last = null;
while (iter1.hasNext() && iter2.hasNext()) {
TreeNode tmp1 = iter1.next();
TreeNode tmp2 = iter2.next();
if (tmp1 != tmp2) {
return last;
}
last = tmp1;
}
// If never find any node which is different, means Node 1 and Node 2 are the same one.
// so just return the last one.
return last;
}
public static boolean LCAPath(TreeNode root, TreeNode node, ArrayList<TreeNode> path) {
// if didn't find, we should return a empty path.
if (root == null || node == null) {
return false;
}
// First add the root node.
path.add(root);
// if the node is in the left side.
if (root != node
&& !LCAPath(root.left, node, path)
&& !LCAPath(root.right, node, path)
) {
// Didn't find the node. should remove the node added before.
path.remove(root);
return false;
}
// found
return true;
}
/*
* * 12. 求二叉树中节点的最大距离:getMaxDistanceRec
*
* 首先我们来定义这个距离:
* 距离定义为:两个节点间边的数目.
* 如:
* 1
* / \
* 2 3
* \
* 4
* 这里最大距离定义为2,4的距离,为3.
* 求二叉树中节点的最大距离 即二叉树中相距最远的两个节点之间的距离。 (distance / diameter)
* 递归解法:
* 返回值设计:
* 返回1. 深度, 2. 当前树的最长距离
* (1) 计算左子树的深度,右子树深度,左子树独立的链条长度,右子树独立的链条长度
* (2) 最大长度为三者之最:
* a. 通过根节点的链,为左右深度+2
* b. 左子树独立链
* c. 右子树独立链。
*
* (3)递归初始条件:
* 当root == null, depth = -1.maxDistance = -1;
*
*/
public static int getMaxDistanceRec(TreeNode root) {
return getMaxDistanceRecHelp(root).maxDistance;
}
public static Result getMaxDistanceRecHelp(TreeNode root) {
Result ret = new Result(-1, -1);
if (root == null) {
return ret;
}
Result left = getMaxDistanceRecHelp(root.left);
Result right = getMaxDistanceRecHelp(root.right);
// 深度应加1, the depth from the subtree to the root.
ret.depth = Math.max(left.depth, right.depth) + 1;
// 左子树,右子树与根的距离都要加1,所以通过根节点的路径为两边深度+2
int crossLen = left.depth + right.depth + 2;
// 求出cross根的路径,及左右子树的独立路径,这三者路径的最大值。
ret.maxDistance = Math.max(left.maxDistance, right.maxDistance);
ret.maxDistance = Math.max(ret.maxDistance, crossLen);
return ret;
}
private static class Result {
int depth;
int maxDistance;
public Result(int depth, int maxDistance) {
this.depth = depth;
this.maxDistance = maxDistance;
}
}
/*
* 13. 由前序遍历序列和中序遍历序列重建二叉树:rebuildBinaryTreeRec
* We assume that there is no duplicate in the trees.
* For example:
* 1
* / \
* 2 3
* /\ \
* 4 5 6
* /\
* 7 8
*
* PreOrder should be: 1 2 4 5 3 6 7 8
* 根 左子树 右子树
* InOrder should be: 4 2 5 1 3 7 6 8
* 左子树 根 右子树
* */
public static TreeNode rebuildBinaryTreeRec(List<Integer> preOrder, List<Integer> inOrder) {
if (preOrder == null || inOrder == null) {
return null;
}
// If the traversal is empty, just return a NULL.
if (preOrder.size() == 0 || inOrder.size() == 0) {
return null;
}
// we can get the root from the preOrder.
// Because the first one is the root.
// So we just create the root node here.
TreeNode root = new TreeNode(preOrder.get(0));
List<Integer> preOrderLeft;
List<Integer> preOrderRight;
List<Integer> inOrderLeft;
List<Integer> inOrderRight;
// 获得在 inOrder中,根的位置
int rootInIndex = inOrder.indexOf(preOrder.get(0));
preOrderLeft = preOrder.subList(1, rootInIndex + 1);
preOrderRight = preOrder.subList(rootInIndex + 1, preOrder.size());
// 得到inOrder左边的左子树
inOrderLeft = inOrder.subList(0, rootInIndex);
inOrderRight = inOrder.subList(rootInIndex + 1, inOrder.size());
// 通过 Rec 来调用生成左右子树。
root.left = rebuildBinaryTreeRec(preOrderLeft, inOrderLeft);
root.right = rebuildBinaryTreeRec(preOrderRight, inOrderRight);
return root;
}
/*
* 14. 判断二叉树是不是完全二叉树:isCompleteBinaryTree, isCompleteBinaryTreeRec
* 进行level traversal, 一旦遇到一个节点的左节点为空,后面的节点的子节点都必须为空。而且不应该有下一行,其实就是队列中所有的
* 元素都不应该再有子元素。
* */
public static boolean isCompleteBinaryTree(TreeNode root) {
if (root == null) {
return false;
}
TreeNode dummyNode = new TreeNode(0);
Queue<TreeNode> q = new LinkedList<TreeNode>();
q.offer(root);
q.offer(dummyNode);
// if this is true, no node should have any child.
boolean noChild = false;
while (!q.isEmpty()) {
TreeNode cur = q.poll();
if (cur == dummyNode) {
if (!q.isEmpty()) {
q.offer(dummyNode);
}
// Dummy node不需要处理。
continue;
}
if (cur.left != null) {
// 如果标记被设置,则Queue中任何元素不应再有子元素。
if (noChild) {
return false;
}
q.offer(cur.left);
} else {
// 一旦某元素没有左节点或是右节点,则之后所有的元素都不应有子元素。
// 并且该元素不可以有右节点.
noChild = true;
}
if (cur.right != null) {
// 如果标记被设置,则Queue中任何元素不应再有子元素。
if (noChild) {
return false;
}
q.offer(cur.right);
} else {
// 一旦某元素没有左节点或是右节点,则之后所有的元素都不应有子元素。
noChild = true;
}
}
return true;
}
/*
* 14. 判断二叉树是不是完全二叉树:isCompleteBinaryTreeRec
*
*
* 我们可以分解为:
* CompleteBinary Tree 的条件是:
* 1. 左右子树均为Perfect binary tree, 并且两者Height相同
* 2. 左子树为CompleteBinaryTree, 右子树为Perfect binary tree,并且两者Height差1
* 3. 左子树为Perfect Binary Tree,右子树为CompleteBinaryTree, 并且Height 相同
*
* Base 条件:
* (1) root = null: 为perfect & complete BinaryTree, Height -1;
*
* 而 Perfect Binary Tree的条件:
* 左右子树均为Perfect Binary Tree,并且Height 相同。
* */
public static boolean isCompleteBinaryTreeRec(TreeNode root) {
return isCompleteBinaryTreeRecHelp(root).isCompleteBT;
}
private static class ReturnBinaryTree {
boolean isCompleteBT;
boolean isPerfectBT;
int height;
ReturnBinaryTree(boolean isCompleteBT, boolean isPerfectBT, int height) {
this.isCompleteBT = isCompleteBT;
this.isPerfectBT = isPerfectBT;
this.height = height;
}
}
/*
* 我们可以分解为:
* CompleteBinary Tree 的条件是:
* 1. 左右子树均为Perfect binary tree, 并且两者Height相同
* 2. 左子树为CompleteBinaryTree, 右子树为Perfect binary tree,并且两者Height差1
* 3. 左子树为Perfect Binary Tree,右子树为CompleteBinaryTree, 并且Height 相同
*
* Base 条件:
* (1) root = null: 为perfect & complete BinaryTree, Height -1;
*
* 而 Perfect Binary Tree的条件:
* 左右子树均为Perfect Binary Tree,并且Height 相同。
* */
public static ReturnBinaryTree isCompleteBinaryTreeRecHelp(TreeNode root) {
ReturnBinaryTree ret = new ReturnBinaryTree(true, true, -1);
if (root == null) {
return ret;
}
ReturnBinaryTree left = isCompleteBinaryTreeRecHelp(root.left);
ReturnBinaryTree right = isCompleteBinaryTreeRecHelp(root.right);
// 树的高度为左树高度,右树高度的最大值+1
ret.height = 1 + Math.max(left.height, right.height);
// set the isPerfectBT
ret.isPerfectBT = false;
if (left.isPerfectBT && right.isPerfectBT && left.height == right.height) {
ret.isPerfectBT = true;
}
// set the isCompleteBT.
/*
* CompleteBinary Tree 的条件是:
* 1. 左右子树均为Perfect binary tree, 并且两者Height相同(其实就是本树是perfect tree)
* 2. 左子树为CompleteBinaryTree, 右子树为Perfect binary tree,并且两者Height差1
* 3. 左子树为Perfect Binary Tree,右子树为CompleteBinaryTree, 并且Height 相同
* */
ret.isCompleteBT = ret.isPerfectBT
|| (left.isCompleteBT && right.isPerfectBT && left.height == right.height + 1)
|| (left.isPerfectBT && right.isCompleteBT && left.height == right.height);
return ret;
}
/*
* 15. findLongest
* 第一种解法:
* 返回左边最长,右边最长,及左子树最长,右子树最长。
* */
public static int findLongest(TreeNode root) {
if (root == null) {
return -1;
}
TreeNode l = root;
int cntL = 0;
while (l.left != null) {
cntL++;
l = l.left;
}
TreeNode r = root;
int cntR = 0;
while (r.right != null) {
cntR++;
r = r.right;
}
int lmax = findLongest(root.left);
int rmax = findLongest(root.right);
int max = Math.max(lmax, rmax);
max = Math.max(max, cntR);
max = Math.max(max, cntL);
return max;
}
/* 1
* 2 3
* 3 4
* 6 1
* 7
* 9
* 11
* 2
* 14
* */
public static int findLongest2(TreeNode root) {
int [] maxVal = new int[1];
maxVal[0] = -1;
findLongest2Help(root, maxVal);
return maxVal[0];
}
// ret:
// 0: the left side longest,
// 1: the right side longest.
static int maxLen = -1;
static int[] findLongest2Help(TreeNode root, int[] maxVal) {
int[] ret = new int[2];
if (root == null) {
ret[0] = -1;
ret[1] = -1;
return ret;
}
ret[0] = findLongest2Help(root.left, maxVal)[0] + 1;
ret[1] = findLongest2Help(root.right, maxVal)[1] + 1;
//maxLen = Math.max(maxLen, ret[0]);
//maxLen = Math.max(maxLen, ret[1]);
maxVal[0] = Math.max(maxVal[0], ret[0]);
maxVal[0] = Math.max(maxVal[0], ret[1]);
return ret;
}
}
转 http://blog.sina.com.cn/s/blog_eb52001d0102v1si.html
-
顶
- 0
-
踩
- 0
- 上一篇常用算法时间空间复杂度
- 下一篇数据库内、外连接总结
我的同类文章
http://blog.csdn.net
- •二叉树的常见问题及其解决程序2014-09-29
- •list和vector有什么区别?2014-08-07
- •教你透彻了解红黑树2014-08-02
- •hash_set哈希集合容器2014-08-11
- •经典面试题:设计包含min函数的栈,O(1)空间实现方法2014-08-07
- •找工作知识储备(3)---从头说12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用2014-07-27