二叉树:大厂面试必会的二叉树知识点!


不要纠结,干就完事了,熟练度很重要!!!多练习,多总结!!!

LeetCode104:二叉树的最大深度

给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

解题思路

其经典解法是递归操作!maxDepth(root) = max(maxDepth(root.left), maxDepth(root.right)) + 1没有什么多余的复杂操作,就是这么一行经典代码!但是这里面用到的思想则是类似DFS(深度优先搜索算法),这个也是要求掌握的,下面会一并给出!

代码实现

class Solution {
    public int maxDepth(TreeNode root) {
        if (root==null){
            return 0;
        }
        int left=maxDepth(root.left);
        int right=maxDepth(root.right);
        return Math.max(left,right)+1;
    }
}

二叉树的DFS实现,很重要希望你能掌握!

private List<TreeNode> traversal(TreeNode root) {
     List<TreeNode> res = new ArrayList<>();
     Stack<TreeNode> stack = new Stack<>();
     stack.add(root);
     while (!stack.empty()) {
         TreeNode node = stack.peek();
         res.add(node);
         stack.pop();
        if (node.right != null) {
            stack.push(node.right);
        }
        if (node.left != null) {
            stack.push(node.left);
        }
    }
    return res;
}

LeetCode102:二叉树的层次遍历

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

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

3
/ \

9 20

/ \

15 7
返回其层次遍历结果:[[3],[9,20],[15,7]]

解题思路

二叉树的层次遍历,经典的BFS方法,借助队列来实现!你同样要掌握的哦!再次声明,二叉树的DFS和BFS一定要会!

代码实现

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res=new ArrayList<>();
        if (root==null){
            return res;
        }
        Queue<TreeNode> queue=new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()){
            int queuesize=queue.size();
            List<Integer> tmp=new ArrayList<>();
            for (int i=0;i<queuesize;i++){
                TreeNode node=queue.remove();
                tmp.add(node.val);
                if (node.left!=null){
                    queue.add(node.left);
                }
                if (node.right!=null){
                    queue.add(node.right);
                }
            }
            res.add(new ArrayList<>(tmp));
        }
        return res;
    }
}

LeetCode98:验证二叉搜索树

给定一个二叉树,判断其是否是一个有效的二叉搜索树。

解题思路

首先你要明白二叉搜索树的定义。
二叉搜索树(Binary Search Tree),(又:二叉查找树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;它的左、右子树也分别为二叉搜索树。
是的,不只是满足当前节点的只值大于左子节点的值,更是要整个左子树的值都小于当前节点的值,右子树也是如此!那么开始时,我们需要初始化两个值min和max,对 我们选用long型的MIN_VALUE和MAX_VALUE,然后进行递归求解,每次我们遍历到一个节点,看当前节点是否满足,该节点值大于左子节点并且小于右子节点,不满足返回false,满足那么还需验证该节点的左、右子树是否也满足这个条件

代码实现

class Solution {
    public boolean isValidBST(TreeNode root) {
        if (root==null){
            return true;
        }
        return isBST(root,Long.MIN_VALUE,Long.MAX_VALUE);
    }
    public boolean isBST(TreeNode root,long min,long max){
        if (root==null){
            return true;
        }
        if (min>=root.val||max<=root.val){
            return false;
        }
        return isBST(root.left,min,root.val)&&isBST(root.right,root.val,max);
    }
}

LeetCode700:二叉搜索树中的搜索

给定二叉搜索树(BST)的根节点和一个值。你需要在BST中找到节点值等于给定值的节点。返回以该节点为根的子树。如果节点不存在,则返回 NULL。

解题思路

上面我们了解了二叉搜索树的概念,那么要查找一个节点,我们按照BST的特性即可,即对比查找的值与当前节点值的大小,小于则在左子树中寻找,大于则在右子树中寻找,要么中途找到返回节点,要么遍历到根节点返回null

代码实现

class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        while (root!=null){
            if (root.val==val){
                return root;
            }else if (root.val<val){
                root=root.right;
            }else {
                root=root.left;
            }
        }
        return null;
    }
}

LeetCode450:二叉搜索树中的删除

给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。

一般来说,删除节点可分为两个步骤:
首先找到需要删除的节点;
如果找到了,删除它。
说明:要求算法时间复杂度为 O(h),h 为树的高度。

解题思路

我们要删除BST的一个节点,首先需要找到该节点。而找到之后,会出现三种情况。

1.待删除的节点左子树为空,让待删除节点的右子树替代自己。
2.待删除的节点右子树为空,让待删除节点的左子树替代自己。
3.如果待删除的节点的左右子树都不为空。我们需要找到比当前节点小的最大节点(前驱),来替换自己或者比当前节点大的最小节点(后继),来替换自己。

代码实现

class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        if (root==null){
            return null;
        }
        if (key<root.val){
            root.left=deleteNode(root.left,key);
            return root;
        }
        if (key>root.val){
            root.right=deleteNode(root.right,key);
            return root;
        }
        if (root.right==null){
            return root.left;
        }
        if (root.left==null){
            return root.right;
        }
        TreeNode minNode=root.right;
        while (minNode.left!=null){
            minNode=minNode.left;
        }
        root.val=minNode.val;
        root.right=deleteMinNode(root.right);
        return root;
    }
    public TreeNode deleteMinNode(TreeNode root){
        if (root.left==null){
            TreeNode pRight=root.right;
            root.right=null;
            return pRight;
        }
        root.left=deleteMinNode(root.left);
        return root;
    }
}

LeetCode110:平衡二叉树

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。

解题思路

题目中给了平衡二叉树的概念,左子树与右子树的高度差不超过1,而且是任意一颗子树都需要满足这个条件的!关于二叉树的高度,我们上面已经给出了求解方法!即递归求解中,除了验证当前节点是否满足左右子树高度差不超过1,还需要继续验证其左右子树是否也满足此条件!

代码实现

class Solution {
    public boolean isBalanced(TreeNode root) {
        if (root==null){
            return true;
        }
        int leftDepth=depth(root.left);
        int rightDepth=depth(root.right);
        if (Math.abs(leftDepth-rightDepth)>1){
            return false;
        }
        return isBalanced(root.left)&&isBalanced(root.right);
    }
    public int depth(TreeNode root){
        if (root==null){
            return 0;
        }
        int left=depth(root.left);
        int right=depth(root.right);
        return Math.max(left,right)+1;
    }
}

LeetCode222:完全二叉树的节点个数

给出一个完全二叉树,求出该树的节点个数。
说明:
完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

解题思路

首先我们要知道对于一个满二叉树,其h层一共包含有2^h个节点,那么对于本题来说完全二叉树就是最后一层,并不是每个节点的度都是2,而且节点集中在左边排列。那么我们需要做的就是先求出左右子树的高度,如果出现左右子树高度相等,那么说明左子树是颗满二叉树,叶子节点已经排到右子树了,那么对于总的节点个数就是 2^left-1再加上跟节点,再递归求解右子树!如果左右子树高度不等,即左子树大于右子树高度,那么证明右子树是颗满二叉树,总的节点个数等于2 ^right-1再加上根节点,然后递归求解左子树!

代码实现

class Solution {
    public int countNodes(TreeNode root) {
        if (root==null){
            return 0;
        }
        int left=countLevel(root.left);
        int right=countLevel(root.right);
        if (left==right){
            return (1<<left)+countNodes(root.right);
        }else {
            return (1<<right)+countNodes(root.left);
        }
    }
    public int countLevel(TreeNode root){
        if (root==null){
            return 0;
        }
        int left=countLevel(root.left);
        int right=countLevel(root.right);
        return Math.max(left,right)+1;
    }
}

LeetCode814:二叉树的剪枝

给定二叉树根结点 root ,此外树的每个结点的值要么是 0,要么是 1。返回移除了所有不包含 1 的子树的原二叉树。

解题思路

依据题意,我们要删除的节点一定满足以下条件:该节点左右子树为空,且该节点的值为0,那么将该节点设置为null即可!

代码实现

class Solution {
    public TreeNode pruneTree(TreeNode root) {
        return deal(root);
    }
    public TreeNode deal(TreeNode root){
        if (root==null){
            return null;
        }
        root.left=deal(root.left);
        root.right=deal(root.right);
        if (root.left==null&&root.right==null&&root.val==0){
            return null;
        }
        return root;
    }
}

剑指offer40:最小的k个数

输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

解题思路

这是剑指offer上一道非常高频的题目!解题思路可以借用堆来做,本题需要用到大顶堆!在开始时,堆中元素小于k个时,先向堆中加入元素,由于题目要求最小的k个数,所以我们用大顶堆,每次将堆顶元素与遍历元素相比较,如果遍历元素小于堆顶元素,那么将堆顶元素poll,然后将当前遍历元素加入堆中,否则继续遍历!到最后遍历结束后,堆中留存的k个数就是最小的k个!这个思路一定要掌握!

代码实现

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        if(k>=arr.length){
            return arr;
        }
        if (k==0||arr.length==0){
            return new int[0];
        }
        PriorityQueue<Integer> queue=new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1;
            }
        });
        for (int num:arr){
            if (queue.size()<k){
                queue.add(num);
            }else if (queue.peek()>num){
                queue.poll();
                queue.add(num);
            }
        }
        int[] res=new int[k];
        int index=0;
        for (int num:queue){
            res[index++]=num;
        }
        return res;
    }
}

剑指offer7:重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

解题思路

字节一面上来手撕的第一道题!这你敢说不会? 思路就是依据前序遍历(跟左右,首个元素为根节点)的第一个元素,去中序遍历中查找相应节点(中序为左根右)找到相应节点相当于在中序遍历中找到了根节点的左右子树,然后左右子树中再重复上述思路继续寻找子树的左右子树节点!

代码实现

class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return reconstruct(preorder,0,preorder.length-1,inorder,0,inorder.length-1);
    }
    public TreeNode reconstruct(int[] pre,int startpre,int endpre,int[] in,int startin,int endin){
        if (startpre>endpre||startin>endin){
            return null;
        }
        TreeNode root=new TreeNode(pre[startpre]);
        for (int i=startin;i<=endin;i++){
            if (in[i]==pre[startpre]){
                root.left=reconstruct(pre,startpre+1,startpre+i-startin,in,startin,i-1);
                root.right=reconstruct(pre,startpre+i-startin+1,endpre,in,i+1,endin);
                break;
            }
        }
        return root;
    }
}

剑指offer37:序列化二叉树

请实现两个函数,分别用来序列化和反序列化二叉树。

解题思路

比较容易想到的序列化思路就是前序遍历(根左右),这样反序列化时也好还原树结构。即先取出根节点然后依次取出左右子树节点!

代码实现

public class Codec {

    // Encodes a tree to a single string.

    public String serialize(TreeNode root) {
        if(root==null){
            return "#,";
        }
        StringBuffer res=new StringBuffer(root.val+",");
        res.append(serialize(root.left));
        res.append(serialize(root.right));
        return res.toString();
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        String[] str=data.split(",");
        Queue<String> queue=new LinkedList<>();
        for (int i=0;i<str.length;i++){
            queue.offer(str[i]);
        }
        return pre(queue);
        
    }
    public TreeNode pre(Queue<String> queue){
        String val=queue.poll();
        if (val.equals("#")){
            return null;
        }
        TreeNode node=new TreeNode(Integer.parseInt(val));
        node.left=pre(queue);
        node.right=pre(queue);
        return node;
    }
}

剑指offer34:二叉树中和为某一值的路径

输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。

解题思路

递归一套下来!

代码实现

class Solution {
    List<List<Integer>> res=new ArrayList<>();
    List<Integer> path=new ArrayList<>();
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        recur(root,sum);
        return res;
    }
    public void recur(TreeNode root,int target){
        if (root==null){
            return;
        }
        path.add(root.val);
        target-=root.val;
        if (target==0&&root.left==null&&root.right==null){
            res.add(new ArrayList<>(path));
        }
        recur(root.left,target);
        recur(root.right,target);
        path.remove(path.size()-1);
    }
}

总结

本题来源于Leetcode中 归属于二叉树类型题目。
同许多在算法道路上不断前行的人一样,不断练习,修炼自己!
如有博客中存在的疑问或者建议,可以在下方留言一起交流,感谢各位!

觉得本博客有用的客官,可以给个点赞+收藏哦! 嘿嘿

喜欢本系列博客的可以关注下,以后除了会继续更新面试手撕代码文章外,还会出其他系列的文章!

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值