二叉树相关面试题目之实例总结

编码解决二叉树问题能够帮助我们深入理解递归思想,并能提高代码能力。在这里总结上一周实现的五个小例题,从《程序员代码面试指南》里面挑选出来的。它们是:二叉树的序列化和反序列化、找到二叉树中指定值的最长路径长度、找到二叉树中最大的二叉搜索子树、层序打印、搜索二叉树中两个错误的节点和判断二叉树r1是否包含二叉树r2的全部拓扑结构。

1、二叉树的序列化和反序列化

代码包含二叉树的先序序列化、先序反序列化,以及层序的序列化、层序的反序列化。下面是代码部分:

//先序序列化这棵树
public static String serialByPre(Node root) {//递归实现二叉树的先序序列化
    if (root == null) {
        return "#!";
    }
    String res = root.data + "!";
    res += serialByPre(root.left);
    res += serialByPre(root.right);
    return res;
}

public static Node reconByPreString(String str) {//字符串反序列化二叉树
    String[] vals = str.split("!");
    Queue<String> queue = new LinkedList<String>();
    for (int i = 0; i < vals.length; i++) {
        queue.offer(vals[i]);
    }
    return reconPreOrder(queue);
}

private static Node reconPreOrder(Queue<String> queue) {//对字符串队列,使用递归方法将其反序列化为二叉树
    String value = queue.poll();
    if (value.equals("#")) {
        return null;
    }
    Node head = new Node(Integer.parseInt(value));
    head.left = reconPreOrder(queue);
    head.right = reconPreOrder(queue);
    return head;
}

//层序序列化和反序列化
public static String serialByLevel(Node root){
    if(root == null){
        return "#!";
    }
    Queue<Node> queue = new LinkedList<Node>();
    String ret = root.data+"!";
    queue.offer(root);
    while(!queue.isEmpty()){
        Node top = queue.poll();
        if(top.left != null){
            ret+=top.left.data+"!";
            queue.offer(top.left);
        }else{
            ret+="#!";
        }
        if(top.right != null){
            ret+=top.right.data+"!";
            queue.offer(top.right);
        }else{
            ret+="#!";
        }
    }
    return ret;
}

public static Node reconByLevelString(String str){
    String[] items = str.split("!");
    int index =0;
    Queue<Node> queue = new LinkedList<Node>();//队列暂存Node
    Node head = getNode(items[index++]);
    queue.offer(head);
    while(!queue.isEmpty()){
        Node top = queue.poll();
        top.left=getNode(items[index++]);
        top.right=getNode(items[index++]);
        if(top.left != null){
            queue.offer(top.left);
        }
        if(top.right != null){
            queue.offer(top.right);
        }
    }
    return head;
}

private static Node getNode(String string) {
    if(!string.equals("#")){
        return new Node(Integer.parseInt(string));
    }
    return null;
}

2、找到二叉树中指定值的最长路径长度

给定一个指定的路径长度,二叉树路径中跨越层数的最大值。

// 在二叉树中找到累加和为指定值的最长路径长度
public static int getMaxLength(Node root,int sum){//root-根节点,sum-指定的值
    HashMap<Integer,Integer> sumMap = new HashMap<Integer,Integer>();
    sumMap.put(0, 0);//路径长度为0的最大路径长度为0
    return preOrder(root,sum,0,1,0,sumMap);
}

 private static int preOrder(Node root, int sum, int preSum, int level,
     int maxLen, HashMap<Integer, Integer> sumMap) {//preSum-记录上次统计的值,level-二叉树层数,maxLen-最大路径长度,sumMap-中间变量保存队列
    if(root == null){
        return maxLen;
    }
    int curLen = preSum + root.data;
    if(!sumMap.containsKey(curLen)){
        sumMap.put(curLen, level);
    }
    if(sumMap.containsKey(curLen-sum)){
        maxLen = Math.max(level-sumMap.get(curLen-sum), maxLen);
    }
    maxLen=preOrder(root.left,sum,curLen,level+1,maxLen,sumMap);
    maxLen=preOrder(root.right,sum,curLen,level+1,maxLen,sumMap);
    return maxLen;
}

3、找到二叉树中最大的二叉搜索子树

在二叉树中找到最大的二叉搜索子树,并返回该二叉树搜索子树的头结点。

     // 找到二叉树中最大的搜索二叉子树
    public static Node getMaxSub(Node root){
        if(root == null){
            return null;
        }
        int[] recorde = new int[3];
        return posOrder(root,recorde);

    }

    private static Node posOrder(Node root, int[] recorde) {
    /*
    二叉树后序遍历解决问题。
    recorde记录中间信息,0号位置记录节点个数,1号位置记录最小值,2号位置记录最大值。
    */
        if(root == null){
            recorde[0]=0;
            recorde[1]=Integer.MAX_VALUE;
            recorde[2]=Integer.MIN_VALUE;
            return null;
        }
        int data = root.data;
        Node left = root.left;
        Node right = root.right;
        Node lBST = posOrder(left,recorde);
        int lsize = recorde[0];
        int lmin = recorde[1];
        int lmax = recorde[2];
        Node rBST = posOrder(right,recorde);
        int rsize = recorde[0];
        int rmin = recorde[1];
        int rmax = recorde[2];

        recorde[1]=Math.min(lmin,data);
        recorde[2]=Math.max(rmax, data);
        if(left == lBST && right ==rBST && data>lmax && data<rmin){
            recorde[0]=lsize+rsize +1;
            return root;
        }
        recorde[0]=Math.max(lsize, rsize);
        return lsize >rsize?lBST:rBST;
    }

4、层序打印

   //顺序层序打印
   public static void printByLevel(Node root){
        if(root == null){
            System.out.println("#");
        }
        Queue<Node>  queue = new LinkedList<Node>();
        queue.offer(root);
        Node last = root;
        Node nlast = root;
        while(!queue.isEmpty()){
            Node item = queue.poll();
            System.out.print(item.data+" ");
            if(item.left != null){
                nlast = item.left;
                queue.offer(item.left);
            }
            if(item.right != null){
                nlast = item.right;
                queue.offer(item.right);
            }
            if(item == last){
                System.out.println();
                last = nlast;
            }
        }
    }
    //ZigZag方式层序打印二叉树
    public static void printByLevelZig(Node root){
        if(root == null){
            System.out.println("#");
        }
        Queue<Node>  queue = new LinkedList<Node>();
        Queue<Integer>  tmp  = new LinkedList<Integer>();
        queue.offer(root);
        Node last = root;
        Node nlast = root;
        boolean flag = true;

        while(!queue.isEmpty()){
            Node item = queue.poll();
            //System.out.print(item.data+" ");
            tmp.offer(item.data);
            if(item.left != null){
                nlast = item.left;
                queue.offer(item.left);
            }
            if(item.right != null){
                nlast = item.right;
                queue.offer(item.right);
            }
            if(item == last){
                pirntQueue(tmp,flag);
                flag = !flag;
                last = nlast;
            }
        }
    }

    private static void pirntQueue(Queue<Integer> tmp,boolean flag) {
        if(flag){
            while(!tmp.isEmpty()){
                System.out.print(tmp.poll()+" ");
            }
        }else{
            Object[] arry = new Object[tmp.size()];
            arry=tmp.toArray();
            int length = arry.length;
            for(int i=0; i<length;i++){
                System.out.print((int)arry[length-1-i]+" ");
            }
            tmp.clear();
        }
        System.out.println();
    }

5、搜索二叉树中两个错误的节点

    //调整搜索二叉树中两个错误的节点
    public static Node[] getTwoErrNodes(Node root){
    /*
    中序遍历方式,找到局部逆序的两个位置,找到两个错误节点。
    */
        Node[] errs = new Node[2];
        if(root == null){
            return errs;
        }
        Stack<Node> stack = new Stack<Node>();
        Node pre = null;
        while(!stack.isEmpty() || root !=null){
            if(root != null){
                stack.push(root);
                root = root.left;
            }else{
                root = stack.pop();
                if(pre != null && pre.data > root.data){
                    errs[0]=errs[0]==null?pre:errs[0];
                    errs[1]=root;
                }
                pre=root;
                root=root.right;
            }
        }
        return errs;
    } 

6、判断二叉树r1是否包含二叉树r2的全部拓扑结构

   //判断二叉树r1是否包含二叉树r2的全部拓扑结构     
    public static boolean contains(Node r1,Node r2){
    /*
    递归方式解决问题,将问题转化为父节点和子节点问题。然后,针对左子树和右子树去解决问题。
    */
        if(r1 != null)
            return check(r1,r2)||contains(r1.left,r2)||contains(r1.right,r2);
        else
            return false;
    }


    private static boolean check(Node r1, Node r2) {
        if(r2 == null){
            return true;
        }
        if(r1 == null || r1.data != r2.data){
            return false;
        }
        return check(r1.left,r2.left) && check(r1.right,r2.right);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值