二叉树高频题精讲 | 从入门到熟练掌握二叉树操作2

本系列可作为JAVA学习系列的笔记,文中提到的一些练习的代码,小编会将代码复制下来,大家复制下来就可以练习了,方便大家学习。

点赞关注不迷路!您的点赞、关注和收藏是对小编最大的支持和鼓励!

系列文章目录

JAVA初阶---------已更完

JAVA数据结构 DAY1-集合和时空复杂度

JAVA数据结构 DAY2-包装类和泛型

JAVA数据结构 DAY3-List接口

JAVA数据结构 DAY4-ArrayList

JAVA数据结构 DAY5-LinkedList

JAVA数据结构 DAY6-栈和队列

JAVA数据结构 DAY7-二叉树


拓展目录

手把手教你用 ArrayList 实现杨辉三角:从逻辑推导到每行代码详解

链表高频 6 题精讲 | 从入门到熟练掌握链表操作

二叉树高频题精讲 | 从入门到熟练掌握二叉树操作

二叉树高频题精讲 | 从入门到熟练掌握二叉树操作2


目录

目录

系列文章目录

拓展目录

目录

前言

1.相同的树

2.另一棵树的子树

3.翻转二叉树

4.平衡二叉树

5.对称二叉树

6.二叉树遍历

7.二叉树的层序遍历

8.二叉树最近的公共祖先

总结


前言

小编作为新晋码农一枚,会定期整理一些写的比较好的代码,作为自己的学习笔记,会试着做一下批注和补充,如转载或者参考他人文献会标明出处,非商用,如有侵权会删改!欢迎大家斧正和讨论!

本节,我将分享一下二叉树的习题部分,以及思路详解,在力扣 的运行环境,每一题将会附上练题链接,大家点击即可练习!

1.相同的树

给你两棵二叉树的根节点 pq ,编写一个函数来检验这两棵树是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

题目链接:

https://leetcode.cn/problems/same-tree/description/

提示:

  • 两棵树上的节点数目都在范围 [0, 100]
  • -104 <= Node.val <= 104

严格按照:先结构 → 后值

步骤

  1. 判断结构
    • 都空 → 结构相同 ✅
    • 一个空一个不空 → 结构不同 ❌
  2. 判断值
    • 值不同 → 树不同 ❌
  3. 递归判断左右子树
java 复制代码
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    //假设p的节点树为m,q的节点数为n
    //时间复杂度O(min(m,n))
    public boolean isSameTree(TreeNode p, TreeNode q) {
        //1.先判断结构是否是一样的
        if(p!=null&&q==null||p==null&&q!=null){
            return false;
        }
        //上述if语句如果没有执行 意味着两个引用同时为空或者同时不为空
        if(p==null&&q==null){
            return true;
        }
        //都不为空 判断值是否一样
        if(p.val!=q.val){
            return false;
        }
        //都不为空且值一样
        return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
    }
}

2.另一棵树的子树

给你两棵二叉树 rootsubRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false

二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

题目链接:

https://leetcode.cn/problems/subtree-of-another-tree/description/

子树 = 必须包含某个节点 + 它的所有后代 不能少一个,也不能多一个!

也就是说:子树的空节点,必须和主树某棵子树的空节点 完全对应!

但是,这个情况不是的:

前半部分确实一样!但 主树的 2 有右孩子 5,子树的 2 没有!

结构不一样!isSameTree 返回 false!不是子树!

java 复制代码
//相同的树
    //严格按照:先结构 → 后值
    //步骤
    //判断结构
        //都空 → 结构相同 ✅
        //一个空一个不空 → 结构不同 ❌
    //判断值
        //值不同 → 树不同 ❌
        //递归判断左右子树
    public boolean isSameTree(TreeNode root1,TreeNode root2){
        if(root1==null&&root2==null){
            return true;
        }
        if(root1==null||root2==null){
            return false;
        }
        if(root1.val!=root2.val){
            return false;
        }
        return isSameTree(root1.left,root2.left)&&isSameTree(root1.right,root2.right);
    }

    //给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。
    // 如果存在,返回 true ;否则,返回 false 。
    //二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。
    public boolean isSubTree(TreeNode root,TreeNode root1){
        if(root==null&&root1==null){
            return true;
        }
        if(isSameTree(root,root1)||isSameTree(root.left,root1.left)||isSameTree(root.right,root1.right)) return true;
        return false;
    }

3.翻转二叉树

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

题目链接:

226. 翻转二叉树 - 力扣(LeetCode)

java 复制代码
//给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
    public TreeNode binaryTreeInversion(TreeNode root){
        if(root==null){
            return null;
        }
        TreeNode node=root.left;
        root.left=root.right;
        root.right=node;
        binaryTreeInversion(root.left);
        binaryTreeInversion(root.right);
        return root;
    }

4.平衡二叉树

给定一个二叉树,判断它是否是 平衡二叉树

题目链接:

https://leetcode.cn/problems/balanced-binary-tree/description/

  • 写一个求高度方法 getHeight
  • 判空
  • 算左右高度
  • 差 >1 返回 false
  • 递归判断左右子树
java 复制代码
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    //获取二叉树的高度
    public int nodeHeight(TreeNode root){
        if(root==null){
            return 0;
        }
        int leftHeight=nodeHeight(root.left);
        int rightHeight=nodeHeight(root.right);
        return Math.max(leftHeight,rightHeight)+1;

    }
    //判断是否是平衡树
    public boolean isBalanced(TreeNode root) {
        if(root==null){
            return true;
        }
        int leftheight=nodeHeight(root.left);
        int rightheight=nodeHeight(root.right);
        if(Math.abs(leftheight-rightheight)>1){
            return  false;
        }
        return isBalanced(root.left)&&isBalanced(root.right);
    }
}

5.对称二叉树

给你一个二叉树的根节点 root , 检查它是否轴对称。

题目链接:

101. 对称二叉树 - 力扣(LeetCode)

  • 空树对称
  • 外侧对称(左 ↔ 右)
  • 内侧对称(右 ↔ 左)
  • 值必须相等
java 复制代码
//是否是对称二叉树
    public boolean isSymmetric(TreeNode root) {
        if(root==null){
            return true;
        }
        return isMirror(root.left,root.right);
    }

    public boolean isMirror(TreeNode root1,TreeNode root2){
        if(root1==null&&root2==null){
            return true;
        }
        if(root1==null||root2==null){
            return false;
        }
        if(root1.val!=root2.val){
            return false;
        }
        return isMirror(root1.left,root2.right)&&isMirror(root1.right,root2.left);
    }

6.二叉树遍历

描述

编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中"#"表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。

输入描述:

输入包括1行字符串,长度不超过100。

输出描述:

可能有多组测试数据,对于每组数据, 输出将输入字符串建立二叉树后中序遍历的序列,每个字符后面都有一个空格。 每个输出结果占一行。

  • # = null
  • 先序建树:根 → 左 → 右
  • index 必须全局,每次输入重置为 0
java 复制代码
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    //// 静态内部类(static修饰)
    static class TreeNode{  //关键是static
        public char  val;
        public TreeNode left;//存储左孩子的引用
        public TreeNode right;//存储右孩子的引用
        public TreeNode(char val){
            this.val=val;
            //this.left=null;
            //this.right=null;
            //默认是null
        }
    }
    public static int index=0;
    public static TreeNode createTree(String str){
        char sc=str.charAt(index);
        index++;
        if(sc=='#'){
            return null;
        }
        TreeNode curNode=new TreeNode(sc);
        curNode.left=createTree(str);
        curNode.right=createTree(str);
      return curNode;
    }
    public static void inOrder(TreeNode root) {
        if (root == null) {
            return;
        }
        inOrder(root.left);
        System.out.print(root.val + " ");
        inOrder(root.right);
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        

        // 多组字符串输入(正确写法)
        while (in.hasNext()) {
            String str = in.next();
            index = 0; // 每次重置下标
            TreeNode root = createTree(str);
            inOrder(root);
            System.out.println();
        }

    }
    
}

7.二叉树的层序遍历

描述

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

提示:

  • 树中节点数目在范围 [0, 2000]
  • -1000 <= Node.val <= 1000
java 复制代码
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
 //一层一层处理
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res=new ArrayList<>();
        if(root==null){
            return res;
        }
        // 1. 创建队列
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);

        // 2. 循环遍历
        while(!queue.isEmpty()){
                int size=queue.size();
                List<Integer> curLevel=new ArrayList<>();

                for(int i=0;i<size;i++){
                // 取出队首节点
                TreeNode cur=queue.poll();
                curLevel.add(cur.val);
                // 左孩子不为空,入队
                if (cur.left != null) queue.offer(cur.left);
                // 右孩子不为空,入队
                if (cur.right != null) queue.offer(cur.right);
                }
            res.add(curLevel);
        }
        return res;
    }
}

8.二叉树最近的公共祖先

描述

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:"对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。"

我们用这棵树

bash 复制代码
        A
       / \
      B   C
     /
    D

我们要找:D 和 C 的最近公共祖先 答案应该是:A

正式开始!跟着我走👇

函数入口:lowestCommonAncestor(A, D, C)

第一步:看 A

  • A 不是 null,不是 D,不是 C
  • 递归查左:left = lowestCommonAncestor(B, D, C)
  • 递归查右:right = lowestCommonAncestor(C, D, C)

先处理左边:lowestCommonAncestor(B, D, C)

  • B 不是 null,不是 D,不是 C

  • 递归查左:left = lowestCommonAncestor(D, D, C)

  • 递归查右:right = lowestCommonAncestor(null, D, C)

再处理左边:lowestCommonAncestor(D, D, C)

  • D == D
  • 直接返回 D!

处理右边:lowestCommonAncestor(null, D, C)

  • root == null
  • 直接返回 null!

回到 B 节点

现在我们有:

  • left = D
  • right = null

判断:

  • 不是两边都有
  • 返回 left → D

现在回到 A 的右边:lowestCommonAncestor(C, D, C)

  • C == C
  • 直接返回 C!

最终回到 A 节点!

现在我们手里有:

  • left = D
  • right = C
java 复制代码
if (left != null && right != null) {
    return root;
}
  • 左边 找到了
  • 右边 找到了返回 A!

流程结束

答案就是 A!

java 复制代码
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null||root==q||root==p){
            return root;
        }
        
        TreeNode left=lowestCommonAncestor(root.left,p,q);
        TreeNode right=lowestCommonAncestor(root.right,p,q);
        
        if(left!=null&&right!=null){
            return root;
        }
        return left!=null?left:right;
    }

总结

以上就是今天要讲的内容,本文简单记录了java数据结构,仅作为一份简单的笔记使用,大家根据注释理解,您的点赞关注收藏就是对小编最大的鼓励!

相关推荐
JosieBook2 小时前
【WinForm】C# WinForms 跨线程更新 UI 避坑指南
开发语言·ui·c#
闻道且行之2 小时前
Pytorch之torch.nn.Conv2d详解
人工智能·pytorch·python·深度学习·conv2d
知无不研2 小时前
c++垃圾回收机制
开发语言·c++·智能指针·raii·垃圾回收机制
J2虾虾2 小时前
Springboot项目中循环依赖的问题
java·开发语言
wjs20242 小时前
C 数组:深度解析与应用场景
开发语言
lxh01132 小时前
记忆函数题解
开发语言·javascript·ecmascript
qq_404265833 小时前
Django全栈开发入门:构建一个博客系统
jvm·数据库·python
qq_452396233 小时前
【Python × AI】Prompt Engineering 深度工程化:打造大模型的“确定性”控制链路
人工智能·python·ai·prompt