保安日记之二叉树的基础面试题

在上一条博客中介绍了一些二叉树的基础操作,今天就来写一些与二叉树相关的基础面试题 :

以下代码中二叉树的节点都是如下的结构:

class Node{
    int val=0;
    TreeNode left=null;
    TreeNode right=null;

    public TreeNode(int val) {
        this.val = val;
    }
}

1 . 将二叉树的前序遍历的结果放在一个List中返回

示例:
输入 : [1,null,2,3]
输出 : [1,2,3]

思路 :

① 每次方法递归都要在内存中创建一个新的空间开辟栈帧(栈帧就是包含这次方法调用中的局部变量)

② 某个树的result的内容依赖于左右子树中的遍历结果(左右子树的result)(两个result是不相干的)

③ 先序遍历结果=根节点+左子树的先序结果+右子树的先序结果

	public List<Character> preOrderTraversal(Node root) {
        List<Character> result = new ArrayList<>();
        if (root == null) {
            //空树返回空的List 不是null
            return result;
        }
        //访问根节点.此处的访问操作就是把元素添加到result中
        result.add(root.val);
        //递归访问左子树
        result.addAll(preOrderTraversal(root.left));
        //递归访问右子树
        //把参数中的集合里的所有元素都add到当前集合中
        result.addAll(preOrderTraversal(root.right));
        return result;
    }

注意 :

① addAll 的参数是List , add 的参数是元素

② result 存在的意义是 : 每递归一次都new一个result

③ result.addAll(preOrderTraversal(root.left));可以写成如下的代码:

	List<Character> leftResult=preOrderTraversal(root.left);
        for(Character x:leftResult){
            result.add(x);
        }

2 . 将二叉树的中序遍历的结果放在一个List中返回

示例:
输入 : [1,2,3]
输出 : [2,1,3]

    public List<Character> inOrderTraversal(Node root) {
        List<Character> result = new ArrayList<>();
        if (root == null) {
            return result;
        }
        result.addAll(inOrderTraversal(root.left));
        result.add(root.val);
        result.addAll(inOrderTraversal(root.right));
        return result;
    }

3 . 将二叉树的后序遍历的结果放在一个List中返回

示例:
输入 : [1,2,3]
输出 : [2,3,1]

    public List<Character> postOrderTraveral(Node root){
        List<Character> result=new ArrayList<>();

        if(root==null){
            return result;
        }
        result.addAll(postOrderTraveral(root.left));
        result.addAll(postOrderTraveral(root.right));
        result.add(root.val);
        return result;

    }

4 . 判断两棵树是否相同(结构相同 节点值相同就是相同)

示例 1:
输入 : [1,2,3] , [1,2,3]
输出 : true

示例 2:
输入 : [1,2] , [1,null,2]
输出 : false

思路 :

① 借助递归对问题进行拆分A.val==B.val&&A.left和B.left是否相等&&A.right和B.right是否相等

② 这个代码和先序遍历几乎一模一样 访问操作是比较相等

    public boolean isSameTree(Node p,Node q){
       
        if(p==null&&q==null){
            //都是空树认为相等
            return true;
        }
        //if((p==null&&q!=null)||(p!=null&&q==null)){
            //如果两个树一个为空一个非空,那么最终结果肯定不相等
        if(p==null||q==null){
            //两种写法都可以 由于前面还有一个 p q 均为空的条件限制
            return false;
        }
        //按照递归的方式把问题拆分
        //判断p和q是否相等 => p.val ==q.val&& p.left和q.left相等 &&p.right和q.right相等
        return p.val==q.val &&isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);
    }

5 . 给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。

示例 :

给定的树 s:
 3
/ \
4   5
/ \
1   2
/
0
给定的树 t:
4
/ \
1   2

返回 false。

	public boolean isSubtree(Node s,Node t){
        //先序遍历s这个树,访问到某个节点是时,访问操作就是isSameTree
        if(s==null){
            return false;
        }
        //判定s中是否包含t =>先看s和t是否相同||s.left包含t ||s.right包含t
        //访问当前节点
        return isSameTree(s,t)||
        //递归处理左子树
        isSubtree(s.left,t)||
        //递归处理右子树
        isSubtree(s.right,t);
    }

6 . 求二叉树的最大深度,二叉树的深度为根节点到最远叶子节点的最长路径上的节点数

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

  3
 / \
 9  20
/ \
15 7

返回它的最大深度 3 。

	public int maxDepth(Node root){
        if(root==null){
            return 0;
        }
        if(root.left==null&&root.right==null){
            //叶子节点
            return 1;
        }
        int leftDepth=maxDepth(root.left);
        int rightDepth=maxDepth(root.right);
        return 1+(leftDepth>rightDepth?leftDepth:rightDepth);
    }

注意:

① 代码的执行过程类似于后序遍历 访问根节点的操作是一个稍微复杂一点的计算

② 1+max(左子树的深度,右子树的深度)

7 . 平衡二叉树 , 给定一个二叉树,判断它是否是高度平衡的二叉树 , 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1

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

   3
  / \
  9  20
 / \
15  7

返回 true

思路:

依次遍历每个节点 求节点左右子树高度 计算差值,看这个差值是否符合要求

    public boolean isBalanced(Node root){
        if(root==null){
            return true;
        }
        if(root.left==null&&root.right==null){
            return true;
        }
        //求左右子树的高度
        int leftDepth=maxDepth(root.left);
        int rightDepth=maxDepth(root.right);
        //左右子树高度差<=1&&左子树平衡&&右子树平衡
        return (leftDepth-rightDepth<=1&&leftDepth-rightDepth>=-1)
                &&isBalanced(root.left)
                &&isBalanced(root.right);
    }

8 . 请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。

示例 1:
输入:root = [1,2,2,3,4,4,3]
输出:true

示例 2:
输入:root = [1,2,2,null,3,null,3]
输出:false

思路 :

① 判定一棵树是不是对称的 ,对应节点值相同 左右子树刚好相反 和根节点没关系

② 主要看左右子树是否对称 左右子树根节点值相等&&左子树.left和右子树.right对称&&左子树.right和右子树.left对称

    public boolean isSymmetric(Node root){
        if(root==null){
            return true;
        }
        //把判定root是否对称转换成root.left和root.right是否对称
        return isMirror(root.left,root.right);
    }
    private boolean isMirror(Node t1,Node t2){
        if(t1==null&&t2==null){
            return true;
        }
        if(t1==null||t2==null){
            return false;
        }
        //判定t1和t2是否对称
        return (t1.val==t2.val)&&isMirror(t1.left,t2.right)&&isMirror(t1.right,t2.left);
    }
}

以上就是基于二叉树这种数据结构衍生的基础经典面试题,还有很多进阶操作在之后的博客中进行介绍~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值