前端算法:树(力扣144、94、145、100、104题)

目录

一、树(Tree)

1.介绍

2.特点

3.基本术语

4.种类

二、树之操作

1.遍历

前序遍历(Pre-order Traversal):访问根节点 -> 遍历左子树 -> 遍历右子树。

中序遍历(In-order Traversal):遍历左子树 -> 访问根节点 -> 遍历右子树(用于 BST 时可得到排序结果)。

后序遍历(Post-order Traversal):遍历左子树 -> 遍历右子树 -> 访问根节点。

层序遍历(Level-order Traversal):逐层访问树的节点,通常使用队列实现。

2.插入和删除

3.查找

三、树的力扣算法实战

1.144. 二叉树的前序遍历

2.94. 二叉树的中序遍历

 3.145. 二叉树的后序遍历

4.100. 相同的树

5.104. 二叉树的最大深度


一、树(Tree)

1.介绍

树(Tree)是一种重要的数据结构,广泛应用于计算机科学中。它由节点组成,并且有一个根节点,其他节点通过边连接形成层级关系。

2.特点

  1. 层级关系:树结构是分层的,根节点位于顶层,每个节点可以有多个子节点。
  2. 无环性:树中不存在环,即从一个节点出发不可能回到该节点。
  3. 节点的子节点:每个节点可以有零个或多个子节点。

3.基本术语

  • 根节点:树的顶层节点。
  • 叶子节点:没有子节点的节点。
  • 子节点:某个节点直接连接的下层节点。
  • 兄弟节点:同一父节点的子节点。
  • 高度:树的高度是从根节点到最深叶子节点的最长路径的边数。

4.种类

  1. 树(Tree):一般的树结构,没有特定的限制。

  2. 二叉树(Binary Tree):每个节点最多有两个子节点。

    • 完全二叉树(Complete Binary Tree):除了最后一层外,其他层的节点都填满,最后一层的节点尽量向左排列。
    • 满二叉树(Full Binary Tree):每个节点要么是叶子节点,要么有两个子节点。
    • 非完全二叉树(Incomplete Binary Tree):不是完全二叉树的任意形式。
  3. 二叉搜索树(Binary Search Tree, BST):一种特殊的二叉树,左子树的所有节点值小于根节点,右子树的所有节点值大于根节点。

  4. 自平衡树(Self-balancing Tree):如 AVL 树和红黑树,保持树的高度平衡以优化查找效率。

  5. N 叉树(N-ary Tree):每个节点可以有 N 个子节点的树结构。

  6. Trie(前缀树):一种用于存储字符串的树,常用于快速查找和前缀匹配。

二、树之操作

1.遍历

前序遍历(Pre-order Traversal):访问根节点 -> 遍历左子树 -> 遍历右子树。
    // 前序遍历
    preOrderTraversal(node) {
        if (node) {
            console.log(node.value);
            this.preOrderTraversal(node.left);
            this.preOrderTraversal(node.right);
        }
    }
中序遍历(In-order Traversal):遍历左子树 -> 访问根节点 -> 遍历右子树(用于 BST 时可得到排序结果)。
    // 中序遍历
    inOrderTraversal(node) {
        if (node) {
            this.inOrderTraversal(node.left);
            console.log(node.value);
            this.inOrderTraversal(node.right);
        }
    }
后序遍历(Post-order Traversal):遍历左子树 -> 遍历右子树 -> 访问根节点。

    // 后序遍历
    postOrderTraversal(node) {
        if (node) {
            this.postOrderTraversal(node.left);
            this.postOrderTraversal(node.right);
            console.log(node.value);
        }
    }
层序遍历(Level-order Traversal):逐层访问树的节点,通常使用队列实现。
    // 层序遍历
    levelOrderTraversal() {
        if (!this.root) return;

        const queue = [this.root];
        while (queue.length > 0) {
            const node = queue.shift();
            console.log(node.value);
            if (node.left) queue.push(node.left);
            if (node.right) queue.push(node.right);
        }
    }

2.插入和删除

插入:在二叉搜索树中,插入新节点时需要找到合适的位置,保证 BST 的性质。

    // 插入
    insert(value) {
        const newNode = new TreeNode(value);
        if (this.root === null) {
            this.root = newNode;
            return;
        }
        this.insertNode(this.root, newNode);
    }

    insertNode(node, newNode) {
        if (newNode.value < node.value) {
            if (node.left === null) {
                node.left = newNode;
            } else {
                this.insertNode(node.left, newNode);
            }
        } else {
            if (node.right === null) {
                node.right = newNode;
            } else {
                this.insertNode(node.right, newNode);
            }
        }
    }

删除:删除节点时可能需要重新调整树结构,以保持树的性质,尤其在 BST 中。

    // 删除
    delete(value) {
        this.root = this.deleteNode(this.root, value);
    }

    deleteNode(node, value) {
        if (node === null) {
            return null;
        }
        if (value < node.value) {
            node.left = this.deleteNode(node.left, value);
        } else if (value > node.value) {
            node.right = this.deleteNode(node.right, value);
        } else {
            // 找到要删除的节点
            if (node.left === null && node.right === null) {
                return null; // 无子节点
            }
            if (node.left === null) {
                return node.right; // 只有右子节点
            }
            if (node.right === null) {
                return node.left; // 只有左子节点
            }
            // 找到右子树中的最小节点
            const minNode = this.findMinNode(node.right);
            node.value = minNode.value; // 替换值
            node.right = this.deleteNode(node.right, minNode.value); // 删除最小节点
        }
        return node;
    }

3.查找

在树中查找节点的过程依赖于树的性质。对于二叉搜索树,可以通过比较节点值快速找到目标节点。

    search(value) {
        return this.searchNode(this.root, value);
    }

    searchNode(node, value) {
        if (node === null) {
            return false;
        }
        if (value === node.value) {
            return true;
        }
        return value < node.value
            ? this.searchNode(node.left, value)
            : this.searchNode(node.right, value);
    }

三、树的力扣算法实战

1.144. 二叉树的前序遍历

题目描述:给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

示例 1:

输入:root = [1,null,2,3]

输出:[1,2,3]

示例 2:

输入:root = [1,2,3,4,5,null,8,null,null,6,7,9]

输出:[1,2,4,5,6,7,3,8,9]

示例 3:

输入:root = []

输出:[]

示例 4:

输入:root = [1]

输出:[1]

解题思路:将二叉树进行先序遍历(中左右:根节点->左子树->右子树)

代码:

var preorderTraversal = function(root) {
    const arr = []

    const fun = (node) =>{
        if(node){
            arr.push(node.val)
                fun(node.left)
                fun(node.right)
        }
        
    }

    fun(root)
    return arr
};

2.94. 二叉树的中序遍历

题目描述:给定一个二叉树的根节点 root ,返回 它的 中序 遍历

示例 1:

输入:root = [1,null,2,3]
输出:[1,3,2]

示例 2:

输入:root = []
输出:[]

示例 3:

输入:root = [1]
输出:[1]

解题思路:将二叉树进行中序遍历(左中右:左子树->根节点->右子树)

代码:

var inorderTraversal = function(root) {
    const arr = []
    const fun = (root) =>{
        if(!root) return
        fun(root.left)
        arr.push(root.val)
        fun(root.right)
    }
    fun(root)
    return arr
};

 3.145. 二叉树的后序遍历

题目描述:给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历

示例 1:

输入:root = [1,null,2,3]

输出:[3,2,1]

示例 2:

输入:root = [1,2,3,4,5,null,8,null,null,6,7,9]

输出:[4,6,7,5,2,9,8,3,1]

示例 3:

输入:root = []

输出:[]

示例 4:

输入:root = [1]

输出:[1]

解题思路:将二叉树进行中序遍历(左右中:左子树->右子树->根节点)

代码:

var postorderTraversal = function(root) {
    const arr = []
    const fun = (root) =>{
        if(!root) return
        fun(root.left)
        fun(root.right)
        arr.push(root.val)
    }
    fun(root)
    return arr
};

4.100. 相同的树

题目描述:

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

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

示例 1:

输入:p = [1,2,3], q = [1,2,3]
输出:true

示例 2:

输入:p = [1,2], q = [1,null,2]
输出:false

示例 3:

输入:p = [1,2,1], q = [1,1,2]
输出:false

 解题思路:首先判断两个节点是否都为空,是则返回true;如果一个为空一个不为空,则返回false,再判断两个节点的val值是否相同,不同返回false,依次进行传入两棵树的左节点和右节点

代码:

var isSameTree = function(p, q) {
    if(p === null && q === null) return true;
    if(p === null || q === null) return false
    if(p.val !== q.val) return false
    return isSameTree(p.left,q.left) && isSameTree(p.right,q.right)
};

5.104. 二叉树的最大深度

题目描述:

给定一个二叉树 root ,返回其最大深度。

二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:3

示例 2:

输入:root = [1,null,2]
输出:2

解题思路: 首先判断树是否为空,空则返回0,将树放入栈中,以栈的长度为值进行遍历,将栈的长度定义一个值len,每循环一次计数器num+1,len--,依次弹出stack的栈中元素,判断是否有左右子节点,在将其压入栈中,最后返回num值

代码

var maxDepth = function(root) {
    if(!root) return 0
    const stack = [root]
    let num = 0
    while(stack.length){
        let len = stack.length
        num++
        while(len--){
            const o = stack.shift()
            o.left && stack.push(o.left)
            o.right && stack.push(o.right)
        }
    }
    return num
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【代码审计】常见漏洞专项审计-业务逻辑漏洞审计

❤️博客主页&#xff1a; iknow181 &#x1f525;系列专栏&#xff1a; 网络安全、 Python、JavaSE、JavaWeb、CCNP &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐评论✍ 0x01 漏洞介绍 1、 原理 业务逻辑漏洞是一类特殊的安全漏洞&#xff0c;业务逻辑漏洞属于设计漏洞而非实…

Spring Boot汽车资讯:数字化时代的驾驶

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

Redis的缓存穿透、缓存雪崩、缓存击穿问题及有效解决方案

目录 一、缓存穿透 1.简介 2.解决方案 3.修改前的代码 4.修改过后的代码 二、缓存雪崩 1.简介 2.解决方案 三、缓存击穿 1.简介 2.解决方案 3.用代码来实现互斥锁来解决缓存击穿 4.用代码来实现逻辑过期解决缓存击穿 四、缓存穿透和缓存击穿的区别 一、缓存穿透 …

FPGA 第7讲 简单组合逻辑译码器

时间&#xff1a;2024.11.15 一、学习内容 1.译码器 译码是编码的逆过程&#xff0c;在编码时&#xff0c;每一种二进制代码&#xff0c;都赋予了特定的含义&#xff0c;即都表示了一个确定的信号或者对象。把代码状态的特定含义翻译出来的过程叫做译码&#xff0c;实现译码操…

如何在 Ubuntu 上安装 Jupyter Notebook

本篇文章将教你在 Ubuntu 服务器上安装 Jupyter Notebook&#xff0c;并使用 Nginx 和 SSL 证书进行安全配置。 我将带你一步步在云服务器上搭建 Jupyter Notebook 服务器。Jupyter Notebook 在数据科学和机器学习领域被广泛用于交互式编码、可视化和实验。在远程服务器上运行…

【Pikachu】XML外部实体注入实战

若天下不定&#xff0c;吾往&#xff1b;若世道不平&#xff0c;不回&#xff01; 1.XXE漏洞实战 首先写入一个合法的xml文档 <?xml version "1.0"?> <!DOCTYPE gfzq [<!ENTITY gfzq "gfzq"> ]> <name>&gfzq;</name&…

Docker安装稳定版本nginx-1.26.2

Linux 安装稳定版本nginx-1.20.2 1、下载镜像、场景配置文件目录 [rootTseng ~]# docker pull nginx:1.26.2 1.26.2: Pulling from library/nginx 2d429b9e73a6: Pull complete 40a0d865309c: Pull complete a949b43e642c: Pull complete 8a756fb620a9: Pull complete 93…

训练误差or测试误差与特征个数之间的关系--基于R语言实现

a 生成数据集&#xff0c;数据由 Y X β ϵ YX\beta\epsilon YXβϵ产生&#xff0c;其中 p 20 &#xff0c; n 1000 p20&#xff0c;n1000 p20&#xff0c;n1000 #way1 set.seed(1) p 20 n 1000 x matrix(rnorm(n*p), n, p) B rnorm(p) B[3] 0 B[4] 0 B[9] 0 B[19…

kafka基础

文章目录 一、Kafka入门1.1、JMS1.2、生产者-消费者模式1.3、ZooKeeper 二、kafka基础架构2.1、producer2.2、kafka cluster2.2.1、broker2.2.2、Controller2.2.3、Topic2.2.4、Partition2.2.5、Replication2.2.6、Leader & Follower 2.3、consumer 一、Kafka入门 Kafka是一…

HarmonyOs鸿蒙开发实战(10)=>状态管理-对象数组的属性数据变更刷新UI,基于@Observed 和@ObjectLink装饰器

1.条件:基于HarmonyOs5.0.0版本. 2.功能要求&#xff1a;横向列表中每个景点的名称&#xff08;eg: 第二项 “灵隐寺” &#xff09;, 在通过天气接口拿到对应天气后&#xff0c;拼接到名称后面 > 变成&#xff08;“灵隐寺” 天气&#xff09;&#xff09; 3.老规矩先看…

诡异错误:返回给前端的id被前端自动修改

使用mybatis-plus生成的id&#xff0c;使用雪花算法&#xff0c;是一个long类型的id。 当调用list接口返回给前端后&#xff0c;接口显示数据正常&#xff0c;但是界面上的id不对&#xff0c;多了好几个0&#xff0c;数据都是以0结尾。 由于前端使用vue编写&#xff0c;我不太会…

Django5 2024全栈开发指南(一):框架简介、环境搭建与项目结构

目录 一、Python Web框架要点二、Django流程2.1 Django介绍2.1.1 简介2.1.2 特点2.1.3 MVT模式2.1.4 Django新特性2.1.5 Django学习资料 2.2 搭建Django框架开发环境2.2.1 安装Python语言环境2.2.2 安装Django框架 2.3 创建Django项目2.4 Pycharm创建项目2.5 初试Django52.5.1 …

大模型研究报告 | 2024年中国金融大模型产业发展洞察报告|附34页PDF文件下载

随着生成算法、预训练模型、多模态数据分析等AI技术的聚集融合&#xff0c;AIGC技术的实践效用迎来了行业级大爆发。通用大模型技术的成熟推动了新一轮行业生产力变革&#xff0c;在投入提升与政策扶植的双重作用下&#xff0c;以大模型技术为底座、结合专业化金融能力的金融大…

深入内核讲明白Android Binder【一】

深入内核讲明白Android Binder【一】 前言一、Android Binder应用编写概述二、基于C语言编写Android Binder跨进程通信Demo0. Demo简介1. 服务的管理者server_manager.c2. Binder服务端代码实现 test_service.c2.1 实现思路2.2 完整实现代码 3. Binder客户端代码实现 test_clie…

新一代API开发工具,让API调试更快 更简单

新一代API开发工具 代理调试 请求测试一站式解决方案 Reqable Fiddler Charles Postman, 让API调试更快 &#x1f680; 更简单 &#x1f44c; 直接上下载地址 根据系统,下载对应的版本即可 https://reqable.com/zh-CN/download/

LVGL-从入门到熟练使用

LVGL简介 LVGL&#xff08; Light and Versatile Graphics Library &#xff09;是一个轻量、多功能的开源图形库。 1、丰富且强大的模块化图形组件&#xff1a;按钮 、图表 、列表、滑动条、图片等 2、高级的图形引擎&#xff1a;动画、抗锯齿、透明度、平滑滚动、图层混合等…

从视频帧生成点云数据、使用PointNet++模型提取特征,并将特征保存下来的完整实现。

文件地址 https://github.com/yanx27/Pointnet_Pointnet2_pytorch?spm5176.28103460.0.0.21a95d27ollfze Pointnet_Pointnet2_pytorch\log\classification\pointnet2_ssg_wo_normals文件夹改名为Pointnet_Pointnet2_pytorch\log\classification\pointnet2_cls_ssg "E:…

时间序列关于可解释性值得关注的论文汇总-第2篇

前言 这是时序可解释性论文汇总的第二篇&#xff0c;第一篇见这里&#xff08;后台回复&#xff1a;“论文合集”可直接获取整理的文章&#xff09;。深度学习的可解释性研究一直是热门&#xff0c;而时间序列的可解释性同样非常重要。这是因为时序模型被大量应用到特定领域&a…

DataStream编程模型之数据源、数据转换、数据输出

Flink之DataStream数据源、数据转换、数据输出&#xff08;scala&#xff09; 0.前言–数据源 在进行数据转换之前&#xff0c;需要进行数据读取。 数据读取分为4大部分&#xff1a; &#xff08;1&#xff09;内置数据源&#xff1b; 又分为文件数据源&#xff1b; socket…

Java面试题2024-Java基础

Java基础 1、 Java语言有哪些特点 1、简单易学、有丰富的类库 2、面向对象&#xff08;Java最重要的特性&#xff0c;让程序耦合度更低&#xff0c;内聚性更高&#xff09; 3、与平台无关性&#xff08;JVM是Java跨平台使用的根本&#xff09; 4、可靠安全 5、支持多线程 2、…