保安日记之二叉树进阶面试题(上)

一、前言

关于二叉树的的基本操作以及初阶的面试题在前面的博客已经介绍完毕,这篇博客用二叉树这种数据结构来解决一些更加复杂的编程问题

二、二叉树的层序遍历

2.1 题目

给你一个二叉树,请你返回其按 层序遍历 得到的节点值(即逐层地,从左到右访问所有节点)。

示例:
二叉树:[3,9,20,null,null,15,7],

     3
    / \
    9  20
   / \
   15 7

返回其层次遍历结果:

[
[3],
[9,20],
[15,7]
]

2.2 实现原理

解决方法还是先序遍历 加上一个辅助参数 用来表示当前节点的层数 根据这个层数来决定这个节点应该在哪行

2.3 代码实现

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private List<List<Integer>> result=new ArrayList<>();
    public List<List<Integer>> levelOrder(TreeNode root) {
        if(root==null){
            return result;
        }
        //最好加上clear 防止多组数据的操作
        result.clear();
        levelOderHelper(root,0);
        return result;
    }
    private void levelOderHelper(TreeNode root,int level){
        if(level==result.size()){
            //当前level在result中没有对应的行
            //防止下面的get操作 出现下标越界
            //第一次调用当前方法level是0 result.size()也是0,如果没有add操作 此时get(level)就会触发下标越界异常
            //首次访问到这一行时add 后续再访问的时候已经存在就不要创建了
            result.add(new ArrayList<>());
        }
        List<Integer> curRow=result.get(level);
        curRow.add(root.val);//先序遍历的"访问操作"
        if(root.left!=null){
            levelOderHelper(root.left,level+1);
        }
        if(root.right!=null){
            levelOderHelper(root.right,level+1);
        }
    }
}

三、二叉树的层序遍历

3.1 实现原理

① 借助队列 , 不是递归
② 循环执行以下操作 :
a 取出队首元素
b 访问这个该元素
c 把当前元素的左子树和右子树分别入队列
d 队列为空就是遍历完毕

3.2 代码实现

	public void levelOrder(Node root) {
        if(root==null){
            return;
        }
        //1.创建一个队列
        Queue<Node> queue =new LinkedList<>();
        queue.offer(root);
        //2.进入循环,循环结束条件为队列为空
        while(!queue.isEmpty()){
            //a取出队首元素
            Node cur=queue.poll();
            //b 访问当前元素
            System.out.println(cur.val+" ");
            //c把当前节点左右子树入队列
            if(cur.left!=null){
                queue.offer(cur.left);
            }
            if(cur.right!=null){
                queue.offer(cur.right);
            }
        }
    }

四、判断一棵树是不是完全二叉树

4.1 实现原理

① 基于层序遍历实现的
② 有两个阶段 , 针对这个树进行层序遍历 :
a.要求每个访问到的节点必须具备两个子树,
b.如果遇到某个节点没有子树 , 或者只有左子树就进入第二阶 , 如果只有右子树判定完毕 , 这个树不是完全二叉树
c.第二阶段要求访问到的节点必须没有子树 , 如果有子树就不是完全二叉树
d.直到遍历结束也没有找到不符合要求的节点 , 这个树就是完全二叉树

4.2 代码实现

	public boolean isComplete(Node root) {
        if(root==null){
            return true;
        }
        //这个变量为true 表示当前在第一阶段 为false就是第二阶段
        boolean isFirstStep=true;
        //针对这个树进行层序遍历
        Queue<Node> queue=new LinkedList<>();
        queue.offer(root);

        while(!queue.isEmpty()){
            Node cur=queue.poll();
            if(isFirstStep){
                //第一阶段,要求任意节点必须具备两个子树
                if(cur.left!=null&&cur.right!=null){
                    //当前节点有两个子树,直接把子树入队列,然后往后遍历
                    queue.offer(cur.left);
                    queue.offer(cur.right);
                }else if(cur.left==null&&cur.right!=null){
                    //当前节点右子树非空 左子树为空
                    return false;
                }else if(cur.left!=null&&cur.right==null){
                    isFirstStep=false;
                    queue.offer(cur.left);
                }else{
                    //当前节点左右子树都为空,还是进入第二阶段
                    isFirstStep=false;
                }
            }else{
                //第二阶段要求任意节点必须没有子树
                if(cur.left!=null||cur.right!=null){
                    //找到反例 直接判定不是完全二叉树
                    return false;
                }

            }
        }
        //树遍历完也没有找到反例就是完全二叉树
        return true;
    }

五、二叉树的构建及遍历

5.1 题目

要求中序遍历输出结果 , 并且每个元素之间必须使用空格来分割 , 题目给出的先序遍历是包含空树的结果如ABD###C##

5.2 实现原理

不包含空树的先序遍历结果无法构建一棵树 , 二叉树还原的过程本质上还是进行先序遍历 , 访问元素的过程就是创建节点

5.3 代码实现

public class Main {
    static class TreeNode{
        public char val;//根据数据输入结果,树的每个节点都是一个字符
        public TreeNode left;
        public TreeNode right;

        public TreeNode(char val) {
            this.val = val;
        }
    }
    public static void main(String[] args) {
        Scanner scanner =new Scanner(System.in);
        while(scanner.hasNext()){
            //由于在线OJ的输入数据可能有多组,一定要使用循环的方式来处理
            String line=scanner.next();
            //读到先序结果就可以构建树
            //TreeNode root=buildTree(line);
            index=0;//多行输入一定要重新设置成0
            TreeNode root=creatTreePreOrder(line);
            inOrder(root);//输出中序 打印的每个结果要用空格分割
            //每个输出结果占一行
            System.out.println();
        }
    }
    private static void inOrder(TreeNode root){
        if(root==null){
            return;
        }
        inOrder(root.left);
        System.out.print(root.val+" ");
        inOrder(root.right);
    }
    private static int index=0;//帮助我们在递归中记住当前处理到哪个字符
    //入口
    /*private static TreeNode buildTree(String line){
        //输入数据可能存在多组,每次处理一组新的数据都需要从0开始重新计数
        index=0;
        return creatTreePreOrder(line);
    }*/
    //辅助递归方法
    //每递归一次就处理一个节点(从字符串中取出一个指定字符)
    private static TreeNode creatTreePreOrder(String line){
        char ch=line.charAt(index);
        if(ch=='#'){
            //当前节点是个空树
            return null;
        }
        //如果节点非空,就可以访问这个节点 访问操作就是创建节点
        TreeNode node =new TreeNode(ch);
        index++;//为了处理下一个节点
        node.left=creatTreePreOrder(line);
        index++;//再去处理下一个节点
        node.right=creatTreePreOrder(line);
        return node;
    }
} 

这是第一部分关于二叉树进阶面试题的总结,将会持续更新这一数据结构的相关题型~

你可能感兴趣的:(Java,二叉树)