数据结构算法(四) 之 树的 2 道面试题 18 & 19

  • 剑指 Offer 面试题 18(Java 版):树的子结构

题目:输入两棵二叉树 A 和 B,判断 B 是不是 A 的子结构。

例如图中所示的两棵二叉树,由于 A 中有一部分子树的结构和 B 是一样的,因此 B 是 A 的子结构。

数据结构算法(四) 之 树的 2 道面试题 18 & 19_第1张图片
例子

思路:第一步在树 A 中找到与树 B 根结点一样值的结点 R,第二步再判断树 A 中以 R 为根结点的子树是不是包含和树 B 一样的结构。

首先我们试着在树 A 中找到值为 8 的结点。从树 A 的根节点开始遍历,我们发现它的根节点的值就是 8。接着我们就去判断树 A 的根结点下面的子树是不是含有和树 B 一样的结构。在树 A 中,根结点的左子结点的值是 8,而树 B 的根节点的左子结点是 9,对应的两个结点不同。

因此我们仍然要遍历A,接着查找值为 8 的结点。我们在树的第二层中找到一个值为 8 的结点,然后进行第二步的判断,即判断这个结点下面的子树是否含有和树 B 一样结构的子树。于是我们遍历这个结点下面的子树,先后得到两个子结点 9 和 2,这和树 B 的结构完全相同。此时我们在树 A 中找到了一个和树 B 的结构一样的子树,因此树 B 和树 A 的子结构。

show my code

/**
 * 二叉树结点
 * @author innovator
 *
 */
public class BinaryTreeNode {
    public int value;
    public BinaryTreeNode leftNode;
    public BinaryTreeNode rightNode;
    
    public BinaryTreeNode(int value){
        this.value = value ;
    }
}
/**
 * 判断一个树 B 是不是 树 A 的子结构
 * @author innovator
 *
 */
public class SubstructureInTree {

    /**
     * 判断一个树 B 是不是 树 A 的子结构
     * @param root1
     * @param root2
     * @return
     */
    public static boolean hasSubTree(BinaryTreeNode root1,BinaryTreeNode root2){
        //加入树 B 是空,假定包含
        if(root2 == null){
            return true;
        }
        
        if(root1 == null){
            return false;
        }
        
        boolean result = false;
        if(root1 != null && root2 != null){
            //根结点的值一样
            if(root1.value == root2.value){
                //递归判断左右字树是否相同
                result = doesTree1HaveTree2(root1, root2);
                
            }
            
            //如果根节点不一样,那就遍历左右子树,找到根结点的值一样的结点
            if(!result){
                result = hasSubTree(root1.leftNode,root2);
            }
            
            if(!result){
                result = hasSubTree(root1.rightNode, root2);
            }
            
        }
        
        return result;
    }
    
    /**
     * 遍历左子树右子树,判断是否相等
     * @param root1
     * @param root2
     * @return
     */
    public static boolean doesTree1HaveTree2(BinaryTreeNode root1,BinaryTreeNode root2){
        //已经比较完了 B 树的叶子结点
        if(root2 == null){
            return true;
        }
        
        //已经遍历到了 A 树的叶子结点
        if(root1 == null){
            return false;
        }
        
        if(root1.value != root2.value){
            //如果根结点的值不相等,那么不用比较下面的子树了,就是不相等
            return false;
        }
        
        //递归比较左子树,右子树的值
        return doesTree1HaveTree2(root1.leftNode, root2.leftNode) 
                && doesTree1HaveTree2(root1.rightNode, root2.rightNode);
        
    }
    
    public static void main(String[] args){  
        BinaryTreeNode A = new BinaryTreeNode(8);  
        BinaryTreeNode B = new BinaryTreeNode(8); 
        BinaryTreeNode C = new BinaryTreeNode(7);
        BinaryTreeNode D = new BinaryTreeNode(9);
        BinaryTreeNode E = new BinaryTreeNode(2);
        BinaryTreeNode F = new BinaryTreeNode(4);
        BinaryTreeNode G = new BinaryTreeNode(7);
        
        BinaryTreeNode sub = new BinaryTreeNode(8);
        BinaryTreeNode I = new BinaryTreeNode(9);
        BinaryTreeNode J = new BinaryTreeNode(2);
        
        
        A.leftNode = B;  
        A.rightNode = C;
        B.leftNode = D;  
        B.rightNode = E;
        E.leftNode = F;  
        E.rightNode = G;
        
        sub.leftNode = I;  
        sub.rightNode = J;
        
        System.out.println("树 sub 是 树 A 的子结构吗?"+ hasSubTree(A,sub));
    }
}
测试结果
  • 剑指 Offer 面试题 19(Java 版):二叉树的镜像

题目:请完成一个函数,输入一个二叉树,该函数输出它的镜像。

树的镜像是一个比较新的概念,我们未必能够一下子相出求树的镜像的方法。为了能够形成直观的印象,我们可以自己画一棵二叉树,然后根据镜子的经验画出它的镜像。

数据结构算法(四) 之 树的 2 道面试题 18 & 19_第2张图片
image

思路:我们得出求一棵树的镜像的过程:我们先前序遍历这棵树的每个结点,如果遍历的结点有子节点,就交换它的两个子节点,当交换完所有的非叶子结点的左右子节点之后,我们就得到了镜像。

show my code

/**
 * 打印二叉树的镜像
 * @author innovator
 *
 */
public class TreeMirror {

    /**
     * 递归实现打印二叉树镜像
     * @param root
     * @return
     */
    public static void mirrorByDigui(BinaryTreeNode root){
        
        //空树
        if(root == null){
            return;
        }
        
        //叶子结点
        if(root.leftNode == null && root.rightNode == null){
            return;
        }
        
        //交换左右子结点
        BinaryTreeNode temp = root.leftNode;
        root.leftNode = root.rightNode;
        root.rightNode = temp;
        
        //递归交换左结点的左右字树
        if(root.leftNode != null){
            mirrorByDigui(root.leftNode);
        }
        
        //递归交换右结点的左右字树
        if(root.rightNode != null){
            mirrorByDigui(root.rightNode);
        }
        
    }
    
    /**
     * 借助辅助栈(后进先出)循环交换左右字树
     * @param root
     */
    public static void mirrorByStack(BinaryTreeNode root){
         if(root == null){
               return;
           }
         LinkedList stack = new LinkedList();//借助于辅助栈
         BinaryTreeNode current = null;//存放出栈的栈顶元素
         BinaryTreeNode temp = null;  //交换左右结点用的临时变量
         stack.push(root);//将根元素入栈
         
         while(!stack.isEmpty()){
             
            current = stack.pop();//将根元素出栈 交换根元素的左右子树
            //若左右孩子不为空则交换左右孩子
            if(current.leftNode != null || current.rightNode != null){
                temp = current.leftNode;
                current.leftNode = current.rightNode;
                current.rightNode = temp;
            }
         
            //将根元素的左右孩子压入栈中  
            //这里其实是一层一层地交换左右子结点
            if(current.leftNode != null){
                stack.push(current.leftNode);
            }
            if(current.rightNode != null){
                stack.push(current.rightNode);
            }
         }

    }
    
    /**
     * 前序遍历打印
     * @param root
     */
     public static void printPreOrder(BinaryTreeNode root) {
            if (root == null) {
                return;
            } else {
                System.out.print(root.value + " ");
            }
            if (root.leftNode != null) {
                printPreOrder(root.leftNode);
            }
            if (root.rightNode != null) {
                printPreOrder(root.rightNode);
            }
     }
     
     public static void main(String[] args){  
            BinaryTreeNode A = new BinaryTreeNode(8);  
            BinaryTreeNode B = new BinaryTreeNode(6); 
            BinaryTreeNode C = new BinaryTreeNode(10);
            BinaryTreeNode D = new BinaryTreeNode(5);
            BinaryTreeNode E = new BinaryTreeNode(7);
            BinaryTreeNode F = new BinaryTreeNode(9);
            BinaryTreeNode G = new BinaryTreeNode(11);
        
            A.leftNode = B;  
            A.rightNode = C;
            B.leftNode = D;  
            B.rightNode = E;
            C.leftNode = F;  
            C.rightNode = G;

            System.out.println("原始二叉树的前序遍历:");
            printPreOrder(A);
            System.out.println("");
//          mirrorByDigui(A);
            mirrorByStack(A);
            System.out.println("镜像二叉树的前序遍历:");
            printPreOrder(A);
        }
}
结果

你可能感兴趣的:(数据结构算法(四) 之 树的 2 道面试题 18 & 19)