首页 > 编程语言 >Java二叉树经典进阶OJ题解

Java二叉树经典进阶OJ题解

时间:2024-07-24 21:29:49浏览次数:16  
标签:right TreeNode val 题解 二叉树 Java root 节点 left

 

目录

一、判断一颗二叉树是否为对称二叉树

1.题目描述:

2.代码示例:

3.通过演示与分析:

二、根据先序遍历结果构造二叉树

1.题目描述:

2.代码示例:

3.通过演示与分析:

三、层序遍历的非递归实现

1.题目描述:

2.代码示例:

3.通过演示与分析:

四、判断是否为完全二叉树

1.题目描述:

2.代码示例:

3.通过演示与分析:

五、寻找二叉树的最近公共祖先

1.题目描述:

2.代码示例:

3.通过演示与分析:


   

     二叉树由于其结构的递归特性(即一棵树的左右子树仍然可以看作一棵树),使得其许多操作可以通过递归算法实现,下面给出五道java二叉树的经典进阶OJ题及题解供读者参考。

一、判断一颗二叉树是否为对称二叉树

1.题目描述:

2.代码示例:

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 boolean isSymmetric(TreeNode root) {
        return isSymmetricChild(root.left,root.right);

    }
    //判断一棵树是否对称的底层方法
    public boolean isSymmetricChild(TreeNode left,TreeNode right){
        //两棵树根节点都为空则对称,直接返回true
        if(left==null&&right==null){
            return true;
        }
        //两棵树一棵根节点为空,另一颗不为空,不对称直接返回false
        if(left==null&&right!=null||left!=null&&right==null){
            return false;
        }
        //两棵树均不为空,比较节点的值,若不同则不对称,直接返回false
        if(left.val!=right.val){
            return false;
        }
        //递归判断左树的左子树与右树的右子树是否对称,左树的右子树与右树的左子树是否对称
        return isSymmetricChild(left.left,right.right)&&isSymmetricChild(left.right,right.left);
    }
}

3.通过演示与分析:

假设这棵树的节点个数为n,则该算法的时间复杂度为O(n)。

二、根据先序遍历结果构造二叉树

1.题目描述:

2.代码示例:

import java.util.Scanner;
class TreeNode{
    public char val;
    public TreeNode left;
    public TreeNode right;
    public TreeNode(char val){
        this.val=val;
    }
}

public class Main {
    public static int i=0;
    public static TreeNode createTree(String str){
        TreeNode root=null;
        //遍历字符串
        if(str.charAt(i)!='#'){
            //字符表示不为空则创建节点
            root=new TreeNode(str.charAt(i));
            i++;
            //递归创建左子树
            root.left=createTree(str);
            //递归创建右子树
            root.right=createTree(str);
        }else{
            //字符表示为空则不创建节点
            i++;
        }
        return root;

    }
    //中序遍历方法
    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);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) { // 注意 while 处理多个 case
        String str=in.nextLine();
        TreeNode root=createTree(str);
        inorder(root);
        }
    }
}

3.通过演示与分析:

假设这棵树的节点个数为n,则该算法的时间复杂度为O(n)。

三、层序遍历的非递归实现

1.题目描述:

2.代码示例:

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>> ret=new ArrayList<>();
        //根节点为空直接返回空
        if(root==null){
            return ret;
        }
        //创建一个新的队列(这里有向上转型)
        Queue<TreeNode> queue=new LinkedList<>();
        //根节点入队
        queue.offer(root);
        //队列不为空则进入循环
        while(!queue.isEmpty()){
            //创建本一层的List
            List<Integer>list=new ArrayList<>();
            //获取当前队列大小(本层节点个数)
            int size=queue.size();
            //对队列所有节点执行以下操作
            while(size>0){
                //设定cur记录出队节点
                TreeNode cur=queue.poll();
                //将该节点的值放入本层List
                list.add(cur.val);
                //该节点左子树不为空则左子树根节点入队
                if(cur.left!=null){
                    queue.offer(cur.left);
                }
                //该节点右子树不为空则右子树根节点入队
                if(cur.right!=null){
                    queue.offer(cur.right);
                }
                size--;
            }
            //返回值中添加新一层List的引用
            ret.add(list);
        }
        return ret;
    }
}

借助创建队列实现层序遍历的非递归操作。

3.通过演示与分析:

假设这棵树的节点个数为n,则该算法的时间复杂度为O(n)。 

四、判断是否为完全二叉树

1.题目描述:

判断一棵树是否为完全二叉树(定义如下)

完全二叉树是由满二叉树而引出来的,若设二叉树的深度为h除第 h 层外其它各层 (1~h-1) 的结点数都达到最大个数(即1~h-1层为一个满二叉树),第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。

2.代码示例:

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;
    }
}




public class IsCompleteTree {
    public boolean isCompleteTree(TreeNode root){
        //新建一个队列(这里发生了向上转型)
        Queue<TreeNode> queue=new LinkedList<>();
        //根节点为空认为是完全二叉树
        if(root==null){
            return true;
        }
        //根节点入队
        queue.offer(root);
        //队列不为空则进入循环
        while(!queue.isEmpty()){
            //设定cur记录出队元素
            TreeNode cur=queue.poll();
            //遇到空节点中止循环
            if(cur==null){
                break;
            }
            //将cur左子树根节点入队
            queue.offer(cur.left);
            //将cur右子树根节点入队
            queue.offer(cur.right);
        }
        //循环结束后判断队列中是否仍然存在非空节点
        while(!queue.isEmpty()){
            TreeNode cur=queue.peek();
            if(cur!=null){
                //若有非空节点则说明不为完全二叉树
                return false;
            }else{
                queue.poll();
            }
        }
        //程序全部运行完毕说明此树为完全二叉树
        return true;
    }
}

本题思路类似于层序遍历的非递归实现,同样是 借助创建队列实现层序遍历的非递归操作。

3.通过演示与分析:

演示请读者自行尝试。

假设这棵树的节点个数为n,则该算法的时间复杂度为O(n)。 

五、寻找二叉树的最近公共祖先

1.题目描述:

2.代码示例:

方法一:

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 TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) {
        //根节点为空则直接返回空
        if(root==null){
            return null;
        }
        //如果其中有一个根节点等于root,则最近公共祖先即为root
        if(root==p||root==q){
            return root;
        }
        //开始递归判断
        TreeNode leftTreeLowestCommonAncestor=lowestCommonAncestor1(root.left,p,q);
        TreeNode rightTreeLowestCommonAncestor=lowestCommonAncestor1(root.right,p,q);
        if(leftTreeLowestCommonAncestor!=null&&rightTreeLowestCommonAncestor!=null){
            //左右子树返回值都不为空,说明p与q分别位于根节点两侧, 根节点为最近公共祖先
            return root;
        }else if(leftTreeLowestCommonAncestor!=null){
            //左子树有最近公共祖先
            return leftTreeLowestCommonAncestor;
        }else{
            //右子树有最近公共祖先
            return rightTreeLowestCommonAncestor;
        }
    }
}

方法二:

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 TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) {
        //根节点为空则直接返回空
        if(root==null){
            return null;
        }
        //如果其中有一个根节点等于root,则最近公共祖先即为root
        if(root==p||root==q){
            return root;
        }
        //开始递归判断
        TreeNode leftTreeLowestCommonAncestor=lowestCommonAncestor1(root.left,p,q);
        TreeNode rightTreeLowestCommonAncestor=lowestCommonAncestor1(root.right,p,q);
        if(leftTreeLowestCommonAncestor!=null&&rightTreeLowestCommonAncestor!=null){
            //左右子树返回值都不为空,说明p与q分别位于根节点两侧, 根节点为最近公共祖先
            return root;
        }else if(leftTreeLowestCommonAncestor!=null){
            //左子树有最近公共祖先
            return leftTreeLowestCommonAncestor;
        }else{
            //右子树有最近公共祖先
            return rightTreeLowestCommonAncestor;
        }
    }
    public TreeNode lowestCommonAncestor2(TreeNode root,TreeNode p,TreeNode q){
        //根节点为空则直接返回
        if(root==null){
            return root;
        }
        //为两个指定节点分别创建两个存储其各自到根节点路径的栈
        Stack<TreeNode>stackp=new Stack<>();
        getPath(root,p,stackp);
        Stack<TreeNode>stackq=new Stack<>();
        getPath(root,p,stackq);
        //计算两个栈的大小并比较
        int sizep=stackp.size();
        int sizeq=stackq.size();
        //将较长的栈的元素出栈直到元素个数相等
        if(sizep>sizeq) {
            int size = sizep - sizeq;
            while (size != 0) {
                stackp.pop();
                size--;
            }
        }else{
                int size=sizeq-sizep;
                while(size!=0){
                    stackq.pop();
                    size--;
            }
        }
        //将剩余元素全部出栈直到寻找到相同的节点,此节点即为最近公共祖先
        while(!stackp.isEmpty()&&!stackq.isEmpty()){
            if(stackp.peek()==stackq.peek()){
                return stackp.peek();
            }else{
                stackp.pop();
                stackq.pop();
            }
        }
        return null;
    }
    //将指定节点到根节点的路径存放到指定栈的底层方法
    public boolean getPath(TreeNode root, TreeNode node, Stack<TreeNode> stack){
        //为空返回false
        if(root==null){
             return false;
         }
        //将根节点入栈
        stack.push(root);
        //根节点为指定节点则直接返回true
        if(root==node){
            return true;
        }
        //递归左子树,获取路径
        boolean leftFlg=getPath(root.left,node,stack);
        //成功获取到路径,直接返回标志true
        if(leftFlg==true){
            return true;
        }
        //递归右子树,获取路径
        boolean rightFlg=getPath(root.right,node,stack);
        //成功获取到路径,直接返回标志true
        if(rightFlg==true){
            return true;
        }
        //程序全部执行完毕,说明未找到路径,将当前根节点弹出并返回标志false
        stack.pop();
        return false;
    }
}

3.通过演示与分析:

假设这棵树的节点个数为n,则方法一算法的时间复杂度为O(n),方法二的时间复杂度也为O(n)。

以上便是 Java二叉树经典进阶OJ题及题解的全部内容,如有不当,敬请斧正!

标签:right,TreeNode,val,题解,二叉树,Java,root,节点,left
From: https://blog.csdn.net/2301_79698279/article/details/140654143

相关文章

  • dify-on-wechat 数据乱串问题解决记录
    在检查dify-on-wechat应用中的数据乱串问题时,我们发现了一个关键因素:当前端和后端使用的大语言模型不一致时,会导致数据串扰问题。在深入调查和测试后,我们采取了将前后端的大语言模型改为一致的策略。在实施这一改变后,数据乱串的问题得到了有效解决。以下是详细的记录:问题现象:在dif......
  • 【数据结构】树和二叉树
    目录1.前言2.树2.1树的概念2.2树中的重要概念2.3树的表示形式 2.4树的应用3.二叉树3.1概念3.2两种特殊的二叉树3.3二叉树的性质3.4二叉树的存储3.5二叉树的遍历方式3.5.1创建二叉树3.5.2二叉树的遍历3.6二叉树的基本操作4.总结1.前言二叉树是数据结构中......
  • Java基础常见面试题学习(上)
    1、JVMvsJDKvsJRE①Java虚拟机(JVM)是运行Java字节码的虚拟机。JVM有针对不同系统的特定实现(Windows,Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。字节码和不同系统的JVM实现是Java语言“一次编译,随处可以运行”的关键所在。JVM并不是只有一种!只要满足JVM规范,......
  • IPython的跨界魔术:%%javascript命令深度解析
    IPython的跨界魔术:%%javascript命令深度解析IPython,作为Python编程的强大交互式工具,提供了多种魔术命令来扩展其功能。其中,%%javascript魔术命令允许用户在IPythonNotebook中直接执行JavaScript代码,打通了Python和JavaScript两个世界,为数据可视化、Web内容操作等提供了便......
  • 密码学-RSA基础题解题脚本-Python
    importgmpy2#计算大整数模块importlibnumimportrsafromCrypto.PublicKeyimportRSA#安装时安装pycryptodome模块#已知:p,q,e,cdefknown_p_q_e_c():p=int(input('请输入一个素数p:'))q=int(input('请输入另一个素数q:'))e=int(input('请输入公钥e:'))......
  • Java流程控制
    Java流程控制用户交互ScannerScanner类获取用户输入Scanners=newScanner(System.in);通过next()与nextLine()获取输入字符串,读取前一般需要hasNext()与hasNextLine()判断是否还有输入的数据注意导入java.unil.Scanner以及关闭scanner顺序结构选择结构if单选择......
  • JAVA小白自学日记Day9
     1.序列化序列化版本号:serialVersionUID,是一个类的序列化版本号。如果在反序列化时,类的serialVersionUID与序列化时的版本号不匹配,那么会抛出 InvalidClassException 异常,表示类的版本不兼容,无法进行反序列化。如果流量没有定义,JDK会自动给与一个版本号,当该类发生变化(......
  • java连接redis和基础操作命令
    引入依赖<!--引入java连接redis的驱动--><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>4.3.1</version></dependency>单机模式连接redismain(){//连接redis的信息默......
  • java中的一些经典算法code
    //1.importjava.util.LinkedList;importjava.util.Queue;publicclassCandyGame{//定义一个点的类,用于记录位置和当前累计的糖果数量staticclassPoint{intx,y,steps,candies;Point(intx,inty,intsteps,intcandies){......
  • Java后端开发知识点积累20240724
    1.使用流(Stream)API和lambda表达式来从一个dateBaseList列表中提取所有的title字段,并将这些title值收集到一个新的列表中dateBaseList.stream().map(InspectionManageEntity::getTitle).collect(Collectors.toList());2.@PathVariable注解作用@PathVariable是Spring框架中的......