Java二叉树OJ题

news2024/11/15 1:04:23

目录

    • 1. 检查两颗树是否相同
    • 2. 另一颗树的子树
    • 3. 翻转二叉树
    • 4. 判断一颗二叉树是否是平衡二叉树
      • 4.1 时间复杂度为O(n*n)【从上而下递归】
      • 4.2 时间复杂度为O(n)【从下而上递归】
    • 5. 对称二叉树
    • 6. 二叉树的构建及遍历
    • 7. 二叉树创建字符串
    • 8. 两个指定节点的最近公共祖先
      • 8.1 指定结点位置分情况讨论(递归)
      • 8.2 求根到指定结点的路径(栈)
    • 9. 前序与中序构造二叉树
    • 10. 中序与后序构造二叉树

1. 检查两颗树是否相同

力扣100. 相同的树
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

思路:①如果p和q都为空,那么则两个结点相同(都为空,不存在有孩子)
②如果p和q中只有一个为空,那么说明两个结点不同
③如果p和q中存储的值val不相等,则说明两个结点不同
④如果值相同也不能说明两个结点相同,还要继续依照①②③对其左子树和右子树进行递归判断。

代码:

class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        if (p == null && q == null) {
            return true;
        }
        if (p == null && q != null || p != null && q == null) {
            return false;
        }
        if (p.val != q.val) {
            return false;
        }

        return isSameTree(p.left,q.left) && isSameTree(p.right, q.right);
    }
}

2. 另一颗树的子树

力扣572. 另一棵树的子树
给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。
二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

思路:结合判断两棵树是否相同,调用isSame函数。
①首先看两颗树是否是完全相同的树,传入root和subRoot,如果返回为真那么两棵树就是一模一样的树;
②排除第一种一模一样的情况,那么就递归分别判断root的左子树和右子树,一旦遇到返回值为true,就直接返回true,并且结束程序,说明是子树的关系。
代码:

class Solution {
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if(root == null || subRoot == null) {
            return false;
        }
        boolean flag1 = isSame(root,subRoot);
        if(flag1 == true) {
            return true;
        }
        boolean flag2 = isSubtree(root.left,subRoot);
        if(flag2 == true) {
            return true;
        }
         boolean flag3 =isSubtree(root.right,subRoot);
        if(flag3 == true) {
            return true;
        }
        return false;
    
    }
    public boolean isSame(TreeNode p, TreeNode q) {
        if(p == null && q == null) {
            return true;
        }
        if(p == null && q != null || p != null && q == null) {
            return false;
        }
        if(p.val != q.val) {
            return false;
        }
        return isSame(p.left, q.left) && isSame(p.right, q.right);
    }
}

3. 翻转二叉树

力扣226. 翻转二叉树
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
在这里插入图片描述

思路:①如果树为空,则返回空②递归得到树的左节点,递归得到树的右结点,进行交换
代码:

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root == null) {
            return null;
        }
        TreeNode rotl = invertTree(root.left);
        TreeNode rotr = invertTree(root.right);
        root.left = rotr;
        root.right = rotl;
        return root;
    }
}

4. 判断一颗二叉树是否是平衡二叉树

力扣110. 平衡二叉树
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。在这里插入图片描述

4.1 时间复杂度为O(n*n)【从上而下递归】

思路:得到每个结点的左右子树高度,利用Math库中的abs方法求差值绝对值,①绝对值小于2②左子树上的结点也满足绝对值小于2③右子树上的结点也满足绝对值小于2,则为平衡二叉树。
时间复杂度:算高度的时间复杂度是O(n),一共有n个结点要算高度,那么时间复杂度为O(n*n)。【从上往下每个结点都算了高度,时间复杂度很高】

代码:

class Solution {
    public boolean isBalanced(TreeNode root) {
        if(root == null) {
            return true;
        }
        int leftHigh = getHigh(root.left);
        int rightHigh = getHigh(root.right);
        
        return Math.abs(leftHigh - rightHigh) < 2 && isBalanced(root.left) && isBalanced(root.right);
    }

    public int getHigh(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int leftHigh = getHigh(root.left);
        int rightHigh = getHigh(root.right);
        return leftHigh > rightHigh? leftHigh+1 : rightHigh+1;
    }
}

4.2 时间复杂度为O(n)【从下而上递归】

思路:在求高度的过程中就判断是否平衡,如果不满足平衡就返回-1。因为求根的高度的时候,实际上子树的每个结点都已经求过高度了。最后直接调用求高度的方法,传入的参数为根结点,判断是否大于等于0。

代码:

class Solution {
    public boolean isBalanced(TreeNode root) {
        if(root == null) {
            return true;
        }

        return getHigh(root) >= 0;
    }

    public int getHigh(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int leftHigh = getHigh(root.left);
        int rightHigh = getHigh(root.right);
        if (leftHigh >= 0 && rightHigh >= 0 && Math.abs(leftHigh - rightHigh) < 2) {
            return Math.max(leftHigh,rightHigh) + 1;
        }else {
            return -1;
        }
    }
}

5. 对称二叉树

力扣101. 对称二叉树
给你一个二叉树的根节点 root , 检查它是否轴对称。
在这里插入图片描述

思路:写一个判断2个结点是否相同的方法,①如果2个结点都为空那么是相同②如果有且只有一个为空,那么2个结点不相同③如果两个结点的值不相同,则2个两点不相同;依次递归判断结点A的左子树与结点B的右子树,结点A的右子树与结点B的左子树。
代码:

    public boolean isSymmetric(TreeNode root) {
        if (root == null) {
            return true;
        }
        return isSym(root.left,root.right);
    }

    public boolean isSym(TreeNode p, TreeNode q) {
        if (p == null && q == null) {
            return true;
        }
        if (p == null && q != null || p != null && q == null) {
            return false;
        }
        if (p.val != q.val) {
            return false;
        }
        return isSym(p.left,q.right) && isSym(p.right,q.left);
    }

6. 二叉树的构建及遍历

牛客KY11 二叉树遍历
编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。
示例1
输入:
abc##de#g##f###
输出:
c b e g d f a

思路:
在这里插入图片描述
接受输入的字符串,一个一个遍历字符串中的字符,如果字符不是#,那么就递归建立左子树,如果遇见#那就跳过这个字符,进行下一次的递归,左走完了就走右。
代码:

import java.util.Scanner;

class BinaryTreeNode {
    char val;
    BinaryTreeNode left;
    BinaryTreeNode right;

    public BinaryTreeNode(char val) {
        this.val = val;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            String s = scanner.nextLine();
            BinaryTreeNode root = createNode(s);
            inOrder(root);
        }
    }
    public static int i = 0;
    private static BinaryTreeNode createNode(String s) {
        BinaryTreeNode root = null;
        if (s.charAt(i) != '#') {
            root = new BinaryTreeNode(s.charAt(i));
            i++;
            root.left = createNode(s);
            root.right = createNode(s);
        }else {
            i++;
        }
        return root;
    }
    public static void inOrder(BinaryTreeNode root) {
        if (root == null) {
            return;
        }
        inOrder(root.left);
        System.out.print(root.val + " ");
        inOrder(root.right);
    }
}

7. 二叉树创建字符串

力扣606. 根据二叉树创建字符串
给你二叉树的根节点 root ,请你采用前序遍历的方式,将二叉树转化为一个由括号和整数组成的字符串,返回构造出的字符串。
空节点使用一对空括号对 “()” 表示,转化后需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。
在这里插入图片描述
在这里插入图片描述

思路:实例化一个StringBuilder对象,并实现treeStr完成二叉树转字符串的方法。
①如果二叉树的左节点不为空,则需要“(” + 递归左结点 + “)”
②如果二叉树的左节点为空,Ⅰ:右结点也为空,则直接返回;Ⅱ:右节点不为空,则需要给左节点为空的那个位置加上括号“(” “)”,执行下面的另起分支的右节点的情况
③如果二叉树的右结点为空,则什么都不操作
④如果二叉树的右节点不为空,则需要“(” + 递归右结点 + “)”

代码:

    public String tree2str(TreeNode root) {
        StringBuilder stringBuilder = new StringBuilder();
        treeStr(root,stringBuilder);
        return stringBuilder.toString();
    }
    public void treeStr(TreeNode root, StringBuilder stringBuilder) {
        if (root == null) {
            return;
        }
        stringBuilder.append(root.val);
        if (root.left != null) {
            stringBuilder.append("(");
            treeStr(root.left,stringBuilder);
            stringBuilder.append(")");
        }else {
            if (root.right == null) {
                return;
            }else {
                stringBuilder.append("()");
            }
        }
        if (root.right == null) {
            return;
        }else {
            stringBuilder.append("(");
            treeStr(root.right,stringBuilder);
            stringBuilder.append(")");
        }
    }

8. 两个指定节点的最近公共祖先

力扣236. 二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
在这里插入图片描述

8.1 指定结点位置分情况讨论(递归)

思路:存在以下3种情况
在这里插入图片描述

代码:

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == p || root == q) {
            return root;
        }
        if(root == null) {
            return null;
        }
        TreeNode leftNode = lowestCommonAncestor(root.left,p,q);
        TreeNode rightNode = lowestCommonAncestor(root.right,p,q);
        if(leftNode != null && rightNode != null) {
            return root;
        }else if(leftNode != null) {
            return leftNode;
        }else if(rightNode != null) {
            return rightNode;
        }
        return null;
    }
}

8.2 求根到指定结点的路径(栈)

【难点:如何把根结点到指定结点路上的所有结点找到放到栈里面】
思路:把根结点到指定结点的路径存到栈中,其方法的具体实现是如果递归找到了目标结点就返回真,如果走错路径了就弹出栈重新递归。最后得到2个栈,让栈元素多的那个不断出栈直至2个栈元素个数相等,再依次弹出判断是否有结点相同。
代码:

class Solution {
    private boolean getPath(TreeNode root, TreeNode g, Stack<TreeNode> stack) {
        if (root == null || g == null) {
            return false;
        }
        stack.push(root);
        if (root == g) {
            return true;
        }
        boolean leftFlag = getPath(root.left,g,stack);
        if (leftFlag == true) {
            return true;
        }
        boolean rightFlag = getPath(root.right,g,stack);
        if (rightFlag == true) {
            return true;
        }
        stack.pop();
        return false;
    }
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        //分别获取root到p和root到q的路径存储到栈中
        Stack<TreeNode> stack1 = new Stack<>();
        Stack<TreeNode> stack2 = new Stack<>();
        getPath(root,p,stack1);
        getPath(root,q,stack2);
        int size1 = stack1.size();
        int size2 = stack2.size();
        if (size1 > size2) {
            int size = size1 - size2;
            while (size > 0) {
                stack1.pop();
                size--;
            }
        }else {
            int size = size2 - size1;
            while (size > 0) {
                stack2.pop();
                size--;
            }
        }
        //相等了
        while (!stack1.isEmpty()) {
            TreeNode t1 = stack1.pop();
            TreeNode t2 = stack2.pop();

            if (t1.val == t2.val) {
                return t1;
            }
        }
        return null;
    }
}

9. 前序与中序构造二叉树

力扣105. 从前序与中序遍历序列构造二叉树
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。在这里插入图片描述

思路:前序遍历得到根,中序遍历可以区分根的左子树和右子树,再在前序遍历中得到左子树的根,以此类推递归下去。

代码:

class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        TreeNode ret = createTree(preorder,inorder,0,inorder.length-1);
        return ret;
    }
    public int i = 0;
    public TreeNode createTree(int[] preorder, int[] inorder, int ib, int ie) {
        if (ib > ie) {
            return null;
        }
        TreeNode root = new TreeNode(preorder[i]);
        int index = findRoot(inorder,preorder[i]);
        i++;
        root.left = createTree(preorder,inorder,ib,index - 1);
        root.right =createTree(preorder,inorder,index+1,ie);
        return root;
    }
    private int findRoot(int[] inorder, int x) {
        for (int j = 0; j < inorder.length; j++) {
            if (inorder[j] == x) {
                return j;
            }
        }
        return -1;
    }
}

10. 中序与后序构造二叉树

力扣106. 从中序与后序遍历序列构造二叉树
给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。在这里插入图片描述

思路:后序遍历的最后一个结点是根,中序遍历可以区分根的左子树和右子树,依次类推,但是要注意后序遍历序列根的前面是右子树的根,因此要先创建右子树。

代码:

class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        i = postorder.length - 1;
        return createTree(inorder,postorder,0,inorder.length-1);
    }
    public int i = 0;
    private TreeNode createTree(int[] inorder, int[] postorder, int ib, int ie) {
        if (ib > ie) {
            return null;
        }
        TreeNode root = new TreeNode(postorder[i]);
        int index = findRoot(inorder,postorder[i]);
        i--;
        root.right = createTree(inorder,postorder,index+1,ie);
        root.left = createTree(inorder,postorder,ib,index - 1);
        return root;
    }
        private int findRoot(int[] inorder, int x) {
        for (int j = 0; j < inorder.length; j++) {
            if (inorder[j] == x) {
                return j;
            }
        }
        return -1;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/176508.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java入门作业-DAO,读取sql数据库

DAO意思是数据库、访问、对象。有了前后端思想。 需要下载mysql&#xff0c;并下载链接自己设置好密码。可以在navicat等软件链接打开。 材料是jc0122.sql&#xff0c;里面的admin_info是要操作的表。不像上一节需要把数据库文件放到java目录里。数据库只要在本地即可。 一、…

浅析Spring的五大类注解和方法注解

简单的将bean对象存储到Spring容器中&#xff0c;可以使用五大类注解实现&#xff0c;也可以通过Bean方法注解实现。本文重点围绕这几个问题展开&#xff1a;1.为什么需要五大类注解&#xff1f;2.五大类注解之间有没有关系&#xff1f;3.Spring使用五大类注解生成beanName问题…

Linux常见命令 17 - 帮助命令 man,whatis,--help,info,help

目录 1. 查看命令/配置文件帮助信息 man 2. 查看简短的命令帮助信息 whatis 3. 查看简短的命令选项信息 --help 4. 另一查看命令文件帮助信息 info 5. Shell内置帮助命令 help 1. 查看命令/配置文件帮助信息 man [1] 语法&#xff1a;man [命令] 示例&#xff1a;如果想要查…

分享129个ASP源码,总有一款适合您

ASP源码 分享129个ASP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 129个ASP源码下载链接&#xff1a;https://pan.baidu.com/s/1dUPOSf1BudsK-bB4FnGXfQ?pwdg3ae 提取码&#x…

黑马2021-8Vue自学笔记hm

黑马2021-8Vue教程学习笔记 文章目录黑马2021-8Vue教程学习笔记代码和笔记不断更新gitee代码仓库地址备用前端gei忽略提交文件webpack的使用初始化包管理配置文件 package.json下载webpack解决问题dependencies 和 devDependencies区别:在项目中配置webpackWebpack 中的默认约定…

python基础——列表推导式

python基础——列表推导式 文章目录python基础——列表推导式一、实验目的二、实验原理三、实验环境四、实验内容五、实验步骤一、实验目的 掌握Python数据结构&#xff1a;列表推导式的用法。 二、实验原理 列表推导式&#xff08;list comprehension&#xff09;列表推导式…

【Python百日进阶-Web开发-Linux】Day235 - Win11的WSL2中安装Docker

文章目录一、Docker是什么二、Win11安装Docker2.1 官网下载2.2 系统要求&#x1f517;2.2.1 WSL 2 后端2.2.2 Hyper-V 后端和 Windows 容器2.2.3 关于 Windows 容器2.3 在 Windows 上安装 Docker Desktop2.3.1 交互式安装2.3.2 从命令行安装2.4 启动 Docker 桌面三、WSL2的Ubun…

ConcurrentHashMap的死循环问题

文章目录前言1. 情景复现2. 源码解析3. 代码调试4. 原因5. 解决前言 对于ConcurrentHashMap来说&#xff0c;能保证多线程下的安全问题&#xff0c;但是在JDK1.8中还是会出现一个bug&#xff0c;就是computeIfAbsent&#xff0c;下面就来详细说说死循环的原因 1. 情景复现 首…

进阶C语言 第二章-------《进阶指针》 (指针数组、数组指针、函数指针、回调指针)知识点+基本练习题+深入细节+通俗易懂+完整思维导图+建议收藏

绪论 书接上回&#xff0c;通过对数据类型进阶的认识&#xff0c;你肯定对各种数据类型在内存中如何存储有了了解。虽然说&#xff0c;这方面可能对你的编程能力没什么进步。但是&#xff0c;他是一本内功秘籍&#xff0c;当我们遇到了这方面的问题时我们可以知道可能是哪一方面…

使用 Grafana 请求API接口

目的: 使用Grafana 配合JSON API 插件 请求API接口,完成可视化,实现一些简单的请求功能 假设我们想将如下的API接口返回的json数据可视化 这里借用一下 小熊同学的 金融数据接口 用请求如下接口举例 https://api.doctorxiong.club/v1/fund/detail?code000001&startDat…

色环电容读数方法要点总结

🏡《电子元器件学习目录》 目录 1,概述2,读数方法3,颜色对照表3.1,颜色与电容值数字对照关系表3.2,颜色与10的指数数字对照关系表3.3,颜色与误差对照关系表4,总结1,概述 本文简单介绍色环电容的读数方法。 2,读数方法 如下图所示色环电容共有四个色环。最粗的被命名…

36.Isaac教程--复合消息

复合消息 ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html 文章目录复合消息测量类型使用复合消息的示例手臂关节速度基本轨迹命令手臂关节和末端执行器命令CompositeMetric 和 CompositeAtlas组件使用 CompositeMetric 计算距离在 Python 脚本中创…

使用bookdown构建新年日记本

简介 一年多前在 B 站发布了一个视频&#xff0c;预览了一下基于 bookdown 构建的日记本。本打算之后更个文字版本教程。结果一直忘了&#xff0c;最近通过一位读者的了解&#xff0c;打算把这个坑补上。 本文内容将展示如何使用 bookdown 模板并修改成自己的日记本。此外&…

某阿里员工提问:年终绩效自己给自己打3.25,会有什么后果?网友回答:必死无疑,不要犯傻!...

年底评绩效&#xff0c;大多数人都会给自己打高绩效&#xff0c;但有些人却反其道而行之。最近&#xff0c;一位阿里员工提出了这样的问题&#xff1a;自评绩效时给自己打3.25&#xff0c;会有什么后果&#xff1f;希望领导能不按常理出牌&#xff0c;给自己3.75。有人问&#…

HashMap1.7中的线程安全问题

文章目录前言正文前言 下面聊聊JDK1.7HashMap的死循环问题&#xff0c;在这之前首先要知道JDK1.7的HashMap底层是数组 链表的形式的 正文 下面给出JDK1.7的扩容代码 //扩容代码 void resize(int newCapacity) {//旧的数组Entry[] oldTable table;//旧的数组长度int oldCap…

SpringBoot+Vue--引入Element-UI创建首页-笔记2

关于Vue项目目录结构介绍 https://tiantian.blog.csdn.net/article/details/128666429?spm1001.2014.3001.5502 先安装引入Element-UI Element - The worlds most popular Vue UI framework i是install的缩写 安装完成后,可以看到package.json里已经引入 在main.js里引入…

linux系统的结构

Linux系统一般有4个主要部分&#xff1a;内核、shell、文件系统和应用程序。内核、shell和文件系统一起形成了基本的操作系统结构&#xff0c;它们使得用户可以运行程序、管理文件并使用系统。内核内核是操作系统的核心&#xff0c;具有很多最基本功能&#xff0c;它负责管理系…

Java基础之《netty(31)—用netty实现RPC》

一、需求说明 1、dubbo底层使用了netty作为网络通讯框架&#xff0c;要求使用netty实现一个简单的RPC框架。 2、模仿dubbo&#xff0c;消费者和提供者约定接口和协议&#xff0c;消费者远程调用提供者的服务&#xff0c;提供者返回一个字符串&#xff0c;消费者打印提供者返回…

S32G274A spi发送数组值不变问题

官方例程的spi问题 spi发送函数 下面是S32G两个spi从机发送函数 /** * brief SPI/DSPI异步传输。 * 这个函数使用提供的总线参数初始化异步传输 , 通过外部设备。 * param[in] ExternalDevice -指向传输数据的外部设备的指针 * param[in] TxBuffer -发送缓冲区的指针。 * pa…

3.1动态规划--矩阵连乘问题

写在前面&#xff1a;矩阵连乘的要点 1、最优解数组的含义--A[1:n]的最少数乘次数 2、数组的填写方向--斜着填 3、递推方程含义 今天开始动态规划的学习&#xff0c;动态规划与分治法类似&#xff0c;基本思想就是将待求解的问题分成若干子问题&#xff0c;先求解子问题&am…