二叉树入门算法题详解

news2024/12/23 0:28:10

二叉树入门题目详解

首先知道二叉树是什么:

代码随想录 (programmercarl.com)
了解后知道其实二叉树就是特殊的链表,只是每个根节点节点都与两个子节点相连而其实图也是特殊的链表,是很多节点互相连接;这样说只是便于理解和定义,严格来说他们都是不同的数据结构了,在使用中还是要牢记各种数据结构的性质的。

二叉树的存储方式

链式的:

java

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

对于二叉树一定会第一时间想到递归,他们俩是相辅相成,互相存在的

就比如说简单的二叉树遍历就用到了递归

前序遍历:中左右

中序遍历:左中右

后序遍历:左右中

二叉树的递归遍历

// 前序遍历·递归·LC144_二叉树的前序遍历
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<Integer>();
        preorder(root, result);
        return result;
    }

    public void preorder(TreeNode root, List<Integer> result) {
        if (root == null) {
            return;
        }
        result.add(root.val);
        preorder(root.left, result);
        preorder(root.right, result);
    }
}
// 中序遍历·递归·LC94_二叉树的中序遍历
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        inorder(root, res);
        return res;
    }

    void inorder(TreeNode root, List<Integer> list) {
        if (root == null) {
            return;
        }
        inorder(root.left, list);
        list.add(root.val);             // 注意这一句
        inorder(root.right, list);
    }
}
// 后序遍历·递归·LC145_二叉树的后序遍历
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        postorder(root, res);
        return res;
    }

    void postorder(TreeNode root, List<Integer> list) {
        if (root == null) {
            return;
        }
        postorder(root.left, list);
        postorder(root.right, list);
        list.add(root.val);             // 注意这一句
    }
}

二叉树的层序遍历

其实可以说前边的递归遍历是深度遍历,那么层序就是字面意思,一层一层遍历,如何能一层一层遍历呢,我们想到了队列,以及父节点和子节点的关系,即先有父节点,后有子节点,子节点连着父节点,所以

当使用队列时,可以先把父节点放进去,有父节点就可以找出对应的子节点,把父节点的子节点也放进去,再把父节点输出出去,队列中剩下的就是子节点,再找到对应的子子节点,这时就可以把子节点输出出去,聪明点的已经发现了,我们现在输出的顺序就像是层序遍历,是的,层序就是这么一个过程。

这中间需要有一个用来描述此时这层节点个数的变量来中转,因为每层的节点个数都不同,

分为递归和借助队列两种方式

借助队列:更容易理解上边的过程:

class Solution {
    public List<List<Integer>> resList = new ArrayList<List<Integer>>();

    public List<List<Integer>> levelOrder(TreeNode root) {
  
        checkFun02(root);

        return resList;
    }  
//BFS--迭代方式--借助队列
    public void checkFun02(TreeNode node) {
        if (node == null) return;
        Queue<TreeNode> que = new LinkedList<TreeNode>();
        que.offer(node);

        while (!que.isEmpty()) {
            List<Integer> itemList = new ArrayList<Integer>();
            int len = que.size();

            while (len > 0) {
                TreeNode tmpNode = que.poll();
                itemList.add(tmpNode.val);

                if (tmpNode.left != null)  que.offer(tmpNode.left);
                if (tmpNode.right != null) que.offer(tmpNode.right);
                len--;
            }

            resList.add(itemList);
        }

    }

翻转二叉树:

其实就是使用递归先把二叉树的每个左右节点都交换一遍,再遍历一遍,得到的新的就是翻转的

java

class Solution {
   /**
     * 前后序遍历都可以
     * 中序不行,因为先左孩子交换孩子,再根交换孩子(做完后,右孩子已经变成了原来的左孩子),再右孩子交换孩子(此时其实是对原来的左孩子做交换)
     */
    public TreeNode invertTree(TreeNode root) {
        if (root == null) {
            return null;
        }
        //以后序遍历为例
        invertTree(root.left);   //左
        invertTree(root.right);  //右
        swapChildren(root);      //中
        //虽然先遍历左右子树,但第三步到根节点时会改变其左右子树,所以仍然正确,先写中,左右,其实效果是一样的;
        return root;             
    }

    private void swapChildren(TreeNode root) {
        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;
    }
}

对称二叉树

image-20240216202053231

如图

我们可以想象一下后序遍历时,

左侧:5 6 3 4 2 右侧: 4 6 5 3 2 中:1

再结合图片看待,对于左子树其实是按照左右中遍历,

右子树其实可以看做左子树按照右左中的顺序遍历;

所以对于对称二叉树,可以使用后序遍历左子树,并将右子树再按照右左中的顺序遍历,若两者结果一样,那么可以判断是对称二叉树;(找规律,细微之处见斟酌)(想法很不错,现实很骨感,只有后序是不能唯一确认二叉树的);

而对于代码怎么写,是比上边的推理要麻烦一些的,因为,即使两个子树不同,只有先序遍历一种写法,是没办法唯一确认一颗二叉树的!!!

所以我们需要另想办法:再观察,其实递归遍历左子树和右子树,是将每次递归中的左右子树的左右子树对称点的值是否相同,若相同其结果就一样,所以代码条件就变成了,递归遍历二叉树并且每次递归都是带上左右子树,每次都遍历到对称的两边,左节点的子节点应始终和右节点的子节点对称,即:若左为空,右也为空,不为空时,左值应=右值;(过瘾)

java:
(每次先看了c++的代码,再看java写这种链表和二叉树的题目代码是真的复杂。。。)

class Solution {
    public boolean isSymmetric(TreeNode root) {

        return compare(root.left, root.right);
    }

    private boolean compare(TreeNode left, TreeNode right) {

        if (left == null && right != null) {
            return false;
        }
        if (left != null && right == null) {
            return false;
        }

        if (left == null && right == null) {
            return true;
        }
        if (left.val != right.val) {
            return false;
        }
        // 比较外侧
        boolean compareOutside = compare(left.left, right.right);
        // 比较内侧
        boolean compareInside = compare(left.right, right.left);
        return compareOutside && compareInside;
    }
}

参考c++的:

class Solution {
public:
    bool compare(TreeNode* left, TreeNode* right) {
        // 首先排除空节点的情况
        if (left == NULL && right != NULL) return false;
        else if (left != NULL && right == NULL) return false;
        else if (left == NULL && right == NULL) return true;
        // 排除了空节点,再排除数值不相同的情况
        else if (left->val != right->val) return false;

        // 此时就是:左右节点都不为空,且数值相同的情况
        // 此时才做递归,做下一层的判断
        bool outside = compare(left->left, right->right);   // 左子树:左、 右子树:右
        bool inside = compare(left->right, right->left);    // 左子树:右、 右子树:左
        bool isSame = outside && inside;                    // 左子树:中、 右子树:中 (逻辑处理)
        return isSame;
    }
    bool isSymmetric(TreeNode* root) {
        if (root == NULL) return true;
        return compare(root->left, root->right);
    }
};

二叉树的最大深度

image-20240216214740832

怎么求呢?直接使用递归求出根节点对应的最大高度就是该二叉树的最大深度啦

java

class solution {
    /**
     * 递归法
     */
    public int maxDepth(TreeNode root) {
        //空节点高度为0,置为return 0,则叶子结点高度一定都为1,越往上的父节点每次都加1;
        if (root == null) {
            return 0;
        }
        int leftDepth = maxDepth(root.left);    //左
        int rightDepth = maxDepth(root.right);  //右
        return Math.max(leftDepth, rightDepth) + 1; //中:高度为左右中的最大值+1;
    }
}

二叉树的最小深度

方法和求最大深度有点像,又不太一样;

当只把最大改最小时会犯以下的错误。需要对节点的字节点都进行判断,当两子节点都为空时才是叶子节点;

易错点:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

class Solution {
    /**
     * 递归法
     */
    public int minDepth(TreeNode root) {
        //空节点高度为0,置为return 0,则叶子结点高度一定都为1,越往上的父节点每次都加1;
        if (root == null) {//意思是左右节点都为空
            return 0;
        }
        int leftDepth = minDepth(root.left);    //左
        int rightDepth = minDepth(root.right);  //右
        if (root.left==null){// 只有左节点为空,返回的最小值只能为右节点+1
            return rightDepth+1;
        }
        if(root.right ==null){//只有右节点为空,返回的最小值只能为左节点+1
            return leftDepth+1;
        }
        return Math.min(leftDepth, rightDepth) + 1; //中:高度为左右中的最小值+1;
    //
    }
}

完全二叉树的节点个数

image-20240217093540254

image-20240217093604229

仔细思考,这道题其实和求二叉树的最大深度很类似,只不过那道题是取左右深度的最大值,这个就可以写成求左右深度+1(就是这个子树的节点个数了)

class solution {
    /**
     * 递归法
     */
    public int Number(TreeNode root) {
        //空节点高度为0,置为return 0,则叶子结点高度一定都为1,越往上的父节点每次都加1;
        if (root == null) {
            return 0;
        }
        int leftNumber = Number(root.left);    //左
        int rightNumber = Number(root.right);  //右
        return leftNumber+rightNumber + 1; //中:高度为左右中的最大值+1;
    }
}

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

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

相关文章

Sora技术报告——Video generation models as world simulators

文章目录 1. 视频生成模型&#xff0c;可以视为一个世界模拟器2. 技术内容2.1 将可视数据转换成patches2.2 视频压缩网络2.3 Spacetime Latent Patches2.4 Scaling transformers 用于视频生成2.5 可变的持续时间&#xff0c;分辨率&#xff0c;宽高比2.6 抽样的灵活性2.7 改进框…

软件工程师,OpenAI Sora驾到,快来围观

概述 近期&#xff0c;OpenAI在其官方网站上公布了Sora文生视频模型的详细信息&#xff0c;展示了其令人印象深刻的能力&#xff0c;包括根据文本输入快速生成长达一分钟的高清视频。Sora的强大之处在于其能够根据文本描述&#xff0c;生成长达60秒的视频&#xff0c;其中包含&…

【教学类-19-09】20240214《ABAB式-规律黏贴18格-手工纸15*15CM-一页3种图案,AB满,纵向、无边框》(中班)

背景需求 利用15*15CM手工纸制作AB色块手环&#xff08;手工纸自带色彩&#xff09;&#xff0c;一页3个图案&#xff0c;2条为一组&#xff0c;黏贴成一个手环 素材准备 代码展示 # # 作者&#xff1a;阿夏 # 时间&#xff1a;2024年2月14日 # 名称&#xff1a;正方形数字卡…

普中51单片机学习(二)

51单片机介绍 所需基础知识 基础数模电知识&#xff0c;简单的C语言。 PS&#xff1a;如果有不懂的直接通义千问。。。 什么是单片机 在一片集成电路芯片上集成微处理器、存储器、I/O接口电路&#xff0c;从而构成了单芯片微型计算机&#xff0c;即单片机。 学习方法 多实…

LaTeX中的documentclass命令:指定文档的类型和整体布局

诸神缄默不语-个人CSDN博文目录 documentclass 是 LaTeX 中一个基础且重要的命令&#xff0c;用于定义文档的整体布局和样式。这个命令告诉 LaTeX 编译器文档是属于哪一类的&#xff0c;比如是文章、报告、书籍等&#xff0c;每一类都有其预定义的格式和结构。 文章目录 基本语…

Linux常见指令(一)

一、基本指令 1.1ls指令 语法 &#xff1a; ls [ 选项 ][ 目录或文件 ] 功能&#xff1a;对于目录&#xff0c;该命令列出该目录下的所有子目录与文件。对于文件&#xff0c;将列出文件名以及其他信息。 常用选项&#xff1a; -a 列出目录下的所有文件&#xff0c;包括以 .…

LeetCode 100题目(python版本)待续...

一.哈希 1.两数之和 题目 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复…

一个小白的转行Python的经历!

1. 寻找一个导师 导师可以降低你加入一个新行业的成本&#xff0c;帮助你熟悉环境和行业规则&#xff0c;也会鼓励你完成心理方面的转变。 2. 建立新的社交网络 过去的人脉关系会阻碍你的转行&#xff0c;因为他们是以过去对你的认知来评价你。新领域的人脉&#xff0c;会给你提…

HAL库 STM32驱动W25QXX驱动例程

HAL库 STM32驱动W25QXX驱动例程 &#x1f4cd;驱动程序参考&#xff1a;《STM32CubeMX | 基于STM32使用HAL库W25Q128驱动程序》&#x1f511; 驱动方式&#xff1a;硬件SPI方式和SPI DMA方式。&#x1f516;适用于&#xff1a;W25X系列/Q系列芯片:W25Q80、W25Q16、W25Q32、 W25…

rust函数 stuct struct方法 关联函数

本文结合2个代码实例主要介绍了rust函数定义方法&#xff0c;struct结构体定义、struct方法及关联函数等相关基础知识。 代码1&#xff1a; main.rc #[derive(Debug)]//定义一个结构体 struct Ellipse {max_semi_axis: u32,min_semi_axis: u32, }fn main() {//椭圆&#xff0…

第14集《佛说四十二章经》

好&#xff01;请大家打开讲义第十九面&#xff0c;第三十九章、教诲无差。 佛言&#xff1a;学佛道者&#xff0c;佛所言说&#xff0c;皆应信顺。譬如食蜜&#xff0c;中边皆甜。吾经亦尔。 大智慧的佛陀说&#xff0c;佛弟子们在修学过程中&#xff0c;对佛陀所说的一切佛…

面向对象编程(一)

目录 1. 面向对象编程概述(了解) 1.1 程序设计的思路 1.2 由实际问题考虑如何设计程序 2. Java语言的基本元素&#xff1a;类和对象 2.1 类和对象概述 2.2 类的成员概述 2.3面向对象完成功能的三步骤&#xff08;重要&#xff09; 步骤1&#xff1a;类的定义 步骤2&#xff1a;…

什么是数据同步利器DataX,如何使用?

转载至我的博客 https://www.infrastack.cn &#xff0c;公众号&#xff1a;架构成长指南 今天给大家分享一个阿里开源的数据同步工具DataX&#xff0c;在Github拥有14.8k的star&#xff0c;非常受欢迎&#xff0c;官网地址&#xff1a;https://github.com/alibaba/DataX 什么…

c++类和对象新手保姆级上手教学(上)

前言&#xff1a; c其实顾名思义就是c语言的升级版&#xff0c;很多刚学c的同学第一感觉就是比c语言难学很多&#xff0c;其实没错&#xff0c;c里的知识更加难以理解可以说杂且抽象&#xff0c;光是类和对象&#xff0c;看起来容易&#xff0c;但想完全吃透&#xff0c;真的挺…

(免费领源码)java#springboot#mysql医院自助服务系统74853-计算机毕业设计项目选题推荐

目 录 摘要 1 绪论 1.1研究意义 1.2研究背景 1.3springboot框架介绍 1.3论文结构与章节安排 2 医院自助服务系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据流程 3.3.2 业务流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 系统用例分…

java+springboot+vue试题库在线学习系统05umj

技术路线&#xff1a; B/S架构&#xff0c;后端springboot框架&#xff0c;前端Vue.js框架。 主要功能模块&#xff08;至少六大功能&#xff09;&#xff0c;参考任务书并拓展 &#xff08;1&#xff09;用户管理模块&#xff1a;规定不同角色的用户对系统中各个功能模块的使用…

【学网攻】 第(29)节 -- 综合实验二

系列文章目录 目录 系列文章目录 文章目录 前言 一、综合实验 二、实验 1.引入 实验目标 实验设备 实验拓扑图 实验配置 实验验证 文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交换机认识及使用【学网攻】 第(3)节 -- 交换机配置聚合端口【学网攻…

【Make编译控制 06】CMake初步使用

目录 一、概述与安装 二、编译源文件 三、无关文件管理 一、概述与安装 CMake是一个跨平台的项目构建工具&#xff0c;相比于Makefile&#xff0c;CMake更加高级&#xff0c;因为CMake代码在执行的时候是会先翻译生成Makefile文件&#xff0c;再调用Makefile文件完成项目构…

【Python--网络编程之TCP三次握手】

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;Python开发技术 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; Python网络编程之[TCP三次握手] 往期内容代码见资源&#xff0c;效果图如下一、实验要求二、协…

MySQL数据库基础(六):DDL数据库操作

文章目录 DDL数据库操作 一、MySQL的组成结构 二、数据库的基本操作 1、创建数据库 2、查询数据库 3、删除数据库 4、选择数据库 三、总结 DDL数据库操作 一、MySQL的组成结构 注&#xff1a;我们平常说的MySQL&#xff0c;其实主要指的是MySQL数据库管理软件。 一个M…