面试算法:镜像二叉树的检测

作者: 望月从良 | 来源:发表于2017-05-09 13:06 被阅读197次

    更详细的讲解和代码调试演示过程,请参看视频
    如何进入google,算法面试技能全面提升指南

    如果你对机器学习感兴趣,请参看一下链接:
    机器学习:神经网络导论

    有一种特殊的二叉树具备镜像特性,如果你从二叉树的中间切一刀,然后把左边反转到右边,你会发现左右是能够重合的。例如下面的二叉树就具备镜像二叉树的特性:

    这里写图片描述

    而下面的二叉树就不具备镜像特性:


    这里写图片描述

    算法要求是,给定一颗二叉树的根节点,判断该二叉树是否具备镜像特性。

    大家是否还记得,以前我们讲过如何层次遍历一颗二叉树。遍历时,现将根节点加入队列,然后把根节点的左孩子和右孩子分别加入队列,接着把队列里第二个元素的左右孩子依次加入队列,最终我们得到一个由二叉树节点构成的队列。

    要判断一颗二叉树是否具备镜像属性,在层次遍历节点的时候,我们做一次变换,第一次遍历节点时,每次都是把当前节点的左孩子和右孩子依次加入队列末尾。第二次遍历时,节点加入队列的次序做一次调换,先把右孩子加入队列,再把左孩子加入队列,如果两次所形成的队列是一样的话,那么该二叉树就具备镜像属性,举个例子,例如下面二叉树:

    这里写图片描述

    层次遍历上方二叉树时,如果是按照父节点,左子节点,右子节点的次序加入队列的话,那么最终队列如下:

    5->6->6->1->2->1->2->4->3->6->7->8->7->3->4

    如果是按照父节点,右子节点,左子节点的次序加入队列的话,得到的最终队列也是:

    5->6->6->1->2->1->2->4->3->6->7->8->7->3->4

    这两个队列是一样的,所以可以断定二叉树具备镜像属性。以下是算法实现:

    import java.util.ArrayList;
    
    
    public class SymmetricTree {
        private ArrayList<TreeNode> treeList1 = new ArrayList<TreeNode>();
        private ArrayList<TreeNode> treeList2 = new ArrayList<TreeNode>();
        private boolean isSymmetric = false;
        
        private void treeToList(TreeNode root, ArrayList<TreeNode> list, boolean isLeft) {
            list.add(root);
            int pos = 0;
            while (pos < list.size()) {
                TreeNode n = list.get(pos);
                if (n != null) {
                    TreeNode n1;
                    TreeNode n2;
                    if (isLeft) {
                        n1 = n.left;
                        n2 = n.right;
                    } else {
                        n1 = n.right;
                        n2 = n.left;
                    }
                    
                    list.add(n1);
                    list.add(n2);
                }
                
                pos++;
            }
        }
        
        public SymmetricTree(TreeNode root) {
            treeToList(root, treeList1, false);
            //mirrorTree(root);
            treeToList(root, treeList2, true);
            
            isSymmetric = compareList(treeList1, treeList2);
        }
        
        public boolean isSymmetric() {
            return isSymmetric;
        }
        
       
        private boolean compareList(ArrayList<TreeNode>l1, ArrayList<TreeNode> l2) {
            if (l1.size() != l2.size()) {
                return false;
            }
            
            int pos = 0;
            while (pos < l1.size()) {
                TreeNode n1 = l1.get(pos);
                TreeNode n2 = l2.get(pos);
                if (n1 == null && n2 != null) {
                    return false;
                }
                
                if (n1 != null && n2 == null) {
                    return false;
                }
                
                if (n1 == null && n2 == null) {
                    pos++;
                    continue;
                }
                
                if (n1.vaule != n2.vaule) {
                    return false;
                }
                
                pos++;
            }
            
            return true;
        }
    }
    
    

    SymmetricTree 用来判断给定二叉树是否具备镜像属性。它的treeToList接口用来层次遍历二叉树并形成队列,如果isLeft参数的值是true, 那么层次遍历二叉树时,使用的次序是父节点,左子节点,右子节点。如果isLeft的参数值是false,那么层次遍历时,使用的次序就是父节点,右子节点,左子节点。

    compareList 用于比较两个队列,节点的值是否一样,进而得到两个队列是否是等价的。在TreeUtil类中,我们构造一颗本文开头所描述的二叉树:

    public class TreeUtil {
        private TreeNode root = null;
        public void addTreeNode(TreeNode node) {
            if (root == null) {
                root = node;
                return;
            }
            
            TreeNode cur = root, prev = root;
            while (cur != null) {
                prev = cur;
                if (cur.vaule > node.vaule) {
                    cur = cur.left;
                } else {
                    cur = cur.right;
                }
            }
            
            if (prev.vaule > node.vaule) {
                prev.left = node;
            } else {
                prev.right = node;
            }
        }
        
        public TreeNode getTreeRoot() {
            return root;
        }
        
        public TreeNode getSymmetricTree() {
            TreeNode n = new TreeNode(314);
            n.left = new TreeNode(6);
            n.left.right = new TreeNode(2);
            n.left.right.right = new TreeNode(3);
            
            n.right = new TreeNode(6);
            n.right.left = new TreeNode(2);
            n.right.left.left = new TreeNode(3);
            
            return n;
        }
    }
    

    入口函数的代码如下:

    public class BinaryTree {
       public static void main(String[] s) {
              TreeUtil util = new TreeUtil();
              TreeNode r = util.getSymmetricTree();
              
              SymmetricTree sym = new SymmetricTree(r);
              boolean t = sym.isSymmetric();
              System.out.println("is the tree symmetric? : " + t);
       }
    }
    

    上面代码首先构造一颗二叉树,然后把二叉树节点传给SymmetricTree类,如果传入的二叉树具备镜像属性,那么 isSymmetric调用会返回true, 要不然会返回false。

    由于二叉树的层次遍历,需要对每个节点都访问一次,因此算法的时间复杂度是O(n), 算法运行中没有分配新的内存,因此算法的空间复杂度是O(1)。更详细的讲解和代码演示,请参看视频。

    更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号:


    这里写图片描述

    相关文章

      网友评论

      本文标题:面试算法:镜像二叉树的检测

      本文链接:https://www.haomeiwen.com/subject/zuibtxtx.html