面试算法高频02-树

树类型对比

数据结构定义节点特点遍历方式常见操作时间复杂度(平均)时间复杂度(最坏)空间复杂度(最坏)与其他结构关系应用场景
有根节点,分层级,包含父子、兄弟节点及子树关系的非线性数据结构每个节点可有多条分支,连接多个子节点无特定统一遍历顺序,可按需求自定义遍历逻辑查找、插入、删除(操作复杂度因树结构不同差异大)查找、插入、删除: O ( n ) O(n) O(n)(无特殊结构时)查找、插入、删除: O ( n ) O(n) O(n) O ( n ) O(n) O(n)(取决于树中节点数量)Linked List是特殊化的Tree,Tree是特殊化的Graph文件目录结构、组织架构图等场景
二叉树每个节点最多有两个子节点的树结构最多两个子节点,分别为左子节点和右子节点前序(根 - 左 - 右)、中序(左 - 根 - 右)、后序(左 - 右 - 根)查找、插入、删除(操作复杂度与树的形态有关)查找、插入、删除: O ( n ) O(n) O(n)(普通二叉树)查找、插入、删除: O ( n ) O(n) O(n)(例如单支树情况) O ( n ) O(n) O(n)(与树的节点数相关)是树的特殊形式在一些简单的决策树模型、算术表达式树中有应用
二叉搜索树空树或满足左子树节点值小于根节点值,右子树节点值大于根节点值,且左右子树也为二叉搜索树的二叉树除具备二叉树节点特征外,节点值具有有序性中序遍历结果为升序排列,还有前序、后序遍历查询、插入、删除查询、插入、删除: O ( log ⁡ n ) O(\log n) O(logn)查询: O ( n ) O(n) O(n)(树严重不平衡时)
插入、删除: O ( n ) O(n) O(n)(树严重不平衡时)
O ( n ) O(n) O(n)(取决于节点数量)是二叉树的特殊形式用于数据搜索、排序场景,如数据库索引、符号表管理

前中后序遍历

前序遍历、中序遍历和后序遍历是二叉树的三种常见遍历方式,它们的定义和特点如下:

  1. 前序遍历(Pre-order Traversal):按照“根节点 - 左子树 - 右子树”的顺序访问二叉树的节点。即先访问根节点,然后递归地对左子树进行前序遍历,最后递归地对右子树进行前序遍历。这种遍历方式可以用于创建二叉树的副本,或者在处理树的根节点相关操作先于子树操作的场景中使用。 例如,对于二叉树A(根节点),左子树节点B,右子树节点C,前序遍历的顺序就是ABC
  2. 中序遍历(In-order Traversal):访问顺序为“左子树 - 根节点 - 右子树”。先递归地遍历左子树,然后访问根节点,最后递归地遍历右子树。对于二叉搜索树,中序遍历会按升序访问所有节点,因此常用于对二叉搜索树进行排序或有序输出节点值。例如,若二叉树A(根节点),左子树节点B,右子树节点C,中序遍历的顺序就是BAC
  3. 后序遍历(Post-order Traversal):按照“左子树 - 右子树 - 根节点”的顺序进行遍历。先递归地遍历左子树,再递归地遍历右子树,最后访问根节点。后序遍历适用于在处理完子树的所有节点后,再对根节点进行操作的场景,比如计算树中所有节点的值之和,需要先计算左右子树节点值之和,最后加上根节点的值。例如,对于上述二叉树,后序遍历的顺序就是BCA

这三种遍历方式都是基于递归的思想实现的,在实际应用中,可以根据具体需求选择合适的遍历方式来处理二叉树相关的问题。同时,也可以通过栈或其他数据结构将递归遍历转换为非递归的形式进行实现。

def preorder(self, root):if root:self.traverse_path.append(root.val)self.preorder(root.left)self.preorder(root.right)def inorder(self, root):if root:self.inorder(root.left)self.traverse_path.append(root.val)self.inorder(root.right)def postorder(self, root):if root:self.postorder(root.left)self.postorder(root.right)self.traverse_path.append(root.val)

二叉搜索树

二叉搜索树(Binary Search Tree,BST) ,也叫二叉查找树、二叉排序树 ,它要么是空树,要么是满足以下性质的二叉树:

节点值有序性

  • 若左子树不为空,左子树上所有节点的值均小于根节点的值 。
  • 若右子树不为空,右子树上所有节点的值均大于根节点的值 。
  • 且其左、右子树也分别为二叉搜索树。

中序遍历有序性

对二叉搜索树进行中序遍历(左子树 - 根节点 - 右子树 ),会得到一个递增的有序序列 。

这种结构在数据操作上具有优势:

查找操作

与二分查找思想类似,通过和当前节点值比较,若目标值小于当前节点值,在左子树查找;若大于,则在右子树查找 。平均时间复杂度为 O ( log ⁡ n ) O(\log n) O(logn) n n n为节点数) ,但树不平衡退化为链表时,时间复杂度会变为 O ( n ) O(n) O(n)

插入操作

新节点总是作为叶子节点插入。从根节点开始比较,若新节点值小于当前节点值,往当前节点左子树插入;若大于,则往右子树插入 ,直到找到合适位置。平均时间复杂度 O ( log ⁡ n ) O(\log n) O(logn)

删除操作

  • 叶子节点:直接删除 。
  • 只有左子树或右子树的节点:让其子树直接成为其双亲节点的子树 。
  • 左右子树都存在的节点:通常用其右子树最小节点(或左子树最大节点 )替代,再删除该替代节点 。平均时间复杂度 O ( log ⁡ n ) O(\log n) O(logn)

二叉搜索树应用广泛,像数据库系统、文件系统常利用它实现高效的数据检索和管理 。 但它存在不平衡问题,为解决该问题,有AVL树、红黑树等自平衡二叉搜索树变种 。

树的面试题

题目复述

给定二叉树的根节点 root ,按中序遍历(左子树 - 根节点 - 右子树)顺序,返回树中所有节点的值。

最优解

# 定义二叉树节点类
class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = rightclass Solution:def inorderTraversal(self, root):result = []def inorder(root):if root:inorder(root.left)result.append(root.val)inorder(root.right)inorder(root)return result

分析

  • 递归思路:定义内部函数 inorder 实现递归。先判断根节点 root 是否存在,若存在,先递归调用 inorder(root.left) 处理左子树,此时会层层深入左子树,直到叶子节点。然后将当前根节点的值 root.val 添加到结果列表 result ,最后递归调用 inorder(root.right) 处理右子树 。
  • 复杂度:时间复杂度为 O ( n ) O(n) O(n) n n n 为二叉树节点数,因为每个节点都会被访问一次。空间复杂度在最好情况下为 O ( log ⁡ n ) O(\log n) O(logn) (树近似完全平衡时,递归调用栈深度为树高) ,最坏情况下为 O ( n ) O(n) O(n) (树退化为单链表形式,递归调用栈深度等于节点数) 。
  • 优势:相比非递归解法,代码更简洁直观,逻辑清晰,易于理解和编写,在代码简洁性和易维护性上表现出色,所以是本题较优选择。

题目2:二叉树的前序遍历

题目复述

给定一个二叉树的根节点 root ,按照前序遍历(根节点 - 左子树 - 右子树)的顺序,返回树中所有节点的值。

最优解

Python递归解法

# 定义二叉树节点类
class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = rightclass Solution:def preorderTraversal(self, root):result = []def preorder(root):if root:result.append(root.val)preorder(root.left)preorder(root.right)preorder(root)return result
分析
  • 递归思路:在内部函数 preorder 中,先判断 root 是否存在。若存在,首先将根节点的值 root.val 加入结果列表 result ,这体现前序遍历先访问根节点的特点。然后递归调用 preorder(root.left) 访问左子树,再递归调用 preorder(root.right) 访问右子树 。
  • 复杂度:时间复杂度为 O ( n ) O(n) O(n) ,其中 n n n 是二叉树的节点个数,因为要对每个节点进行一次访问操作。空间复杂度方面,最好情况(树完全平衡 )下为 O ( log ⁡ n ) O(\log n) O(logn) ,此时递归调用栈深度为树高;最坏情况(树退化为链表 )下为 O ( n ) O(n) O(n) ,递归调用栈深度等于节点数 。
  • 优势:递归解法代码简洁明了,清晰地遵循前序遍历的逻辑,相比非递归实现(需借助栈模拟递归过程,代码更复杂 ),在理解和编写上更具优势,所以是本题较优的实现方式。

题目3:N 叉树的后序遍历

题目复述

给定一个 N 叉树的根节点 root ,按照后序遍历(左子树 - 右子树 - 根节点 ,这里 N 叉树的多个子树也按类似顺序,先遍历完所有子树,最后访问根节点)的顺序,返回树中所有节点的值。

最优解

Python递归解法

# 定义N叉树节点类
class Node:def __init__(self, val=None, children=None):self.val = valself.children = children if children is not None else []class Solution:def postorder(self, root):result = []def post(root):if root:for child in root.children:post(child)result.append(root.val)post(root)return result
分析
  • 递归思路:定义内部函数 post 实现递归。先判断 root 是否存在,若存在,遍历根节点的所有子节点 root.children ,对每个子节点递归调用 post(child) ,这相当于先处理完所有子树。处理完子树后,将根节点的值 root.val 添加到结果列表 result ,符合后序遍历的逻辑。
  • 复杂度:时间复杂度为 O ( n ) O(n) O(n) n n n 为 N 叉树的节点个数,因为每个节点都会被访问一次。空间复杂度方面,最好情况(树比较平衡 )下为 O ( log ⁡ n ) O(\log n) O(logn) ,此时递归调用栈深度与树高相关;最坏情况(树退化为链表状 )下为 O ( n ) O(n) O(n) ,递归调用栈深度等于节点数。
  • 优势:递归解法代码简洁,很好地契合 N 叉树后序遍历的逻辑,相较于使用栈等数据结构的非递归实现(非递归实现要模拟递归调用栈,逻辑更复杂 ),在代码的可读性和编写难度上更具优势,所以是本题较优的选择。

题目4:N 叉树的前序遍历

题目复述

给定一个 N 叉树的根节点 root ,按照前序遍历(根节点 - 子树 ,依次访问完根节点后,再按顺序访问各个子树)的顺序,返回树中所有节点的值。

最优解

Python递归解法

# 定义N叉树节点类
class Node:def __init__(self, val=None, children=None):self.val = valself.children = children if children is not None else []class Solution:def preorder(self, root):result = []def pre(root):if root:result.append(root.val)for child in root.children:pre(child)pre(root)return result
分析
  • 递归思路:在内部函数 pre 中,先判断 root 是否存在。若存在,首先将根节点的值 root.val 加入结果列表 result ,这体现前序遍历先访问根节点的特点。然后遍历根节点的所有子节点 root.children ,对每个子节点递归调用 pre(child) ,依次访问各个子树。
  • 复杂度:时间复杂度为 O ( n ) O(n) O(n) ,其中 n n n 是 N 叉树的节点个数,因为要对每个节点进行一次访问操作。空间复杂度方面,最好情况(树比较平衡 )下为 O ( log ⁡ n ) O(\log n) O(logn) ,此时递归调用栈深度与树高相关;最坏情况(树退化为链表状 )下为 O ( n ) O(n) O(n) ,递归调用栈深度等于节点数。
  • 优势:递归解法代码简洁直观,清晰地遵循 N 叉树前序遍历的逻辑。相比非递归实现(需借助栈等数据结构来模拟递归过程,代码相对复杂 ),在理解和编写上更简单,所以是本题较优的实现方式。

题目5:验证二叉搜索树

题目复述

给定一个二叉树的根节点 root ,判断其是否为有效的二叉搜索树 。有效二叉搜索树需满足:左子树的所有节点的值均小于根节点的值;右子树的所有节点的值均大于根节点的值;且左、右子树也分别为二叉搜索树。

最优解
# 定义二叉树节点类
class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = rightclass Solution:def isValidBST(self, root):def check(root, min_val, max_val):if not root:return Trueif root.val <= min_val or root.val >= max_val:return Falsereturn check(root.left, min_val, root.val) and check(root.right, root.val, max_val)return check(root, float('-inf'), float('inf'))
分析
  • 递归思路:定义内部函数 check 进行递归验证。check 函数接收当前节点 root ,以及当前节点值的取值范围 min_valmax_val 。每次递归时,先检查当前节点 root 的值是否在合理范围内(大于 min_val 且小于 max_val ),若不满足则返回 False 。然后对左子树递归调用 check ,并更新取值范围为 (min_val, root.val) ,对右子树递归调用 check ,更新取值范围为 (root.val, max_val) 。如果所有节点都满足条件,则返回 True
  • 复杂度:时间复杂度为 O ( n ) O(n) O(n) ,其中 n 是二叉树的节点数,因为需要遍历每个节点进行判断。空间复杂度在最好情况下为 O ( log ⁡ n ) O(\log n) O(logn) (树高度平衡时,递归调用栈深度与树高相关 ),最坏情况下为 O ( n ) O(n) O(n) (树退化为链表时,递归调用栈深度等于节点数) 。
  • 优势:这种递归验证方式代码简洁且逻辑清晰,直接基于二叉搜索树的定义进行判断,相比其他复杂的方法(如先中序遍历再判断结果是否有序,虽然可行但多了一次额外的遍历操作 ),效率更高且代码更紧凑,所以是本题较优的解法。

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

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

相关文章

数论4 组合数

目录 前言 求法一 代码 求法二 代码 求法三 代码 求法四 代码 前言 今天要将最后一部分&#xff0c;主要涉及组合数的四种求法。 前置知识 组合数的通项公式&#xff1a; 组合数的递推公式&#xff1a; 卢卡斯定理&#xff1a; 我们今天需要求的四种求法主要基…

构建自己的私有 Git 服务器:基于 Gitea 的轻量化部署实战指南

对于个人开发者、小型团队乃至企业来说&#xff0c;将项目代码托管在 GitHub、Gitee 等公共平台虽然方便&#xff0c;但也存在一定的隐私与可控性问题。 搭建一套私有 Git 代码仓库系统&#xff0c;可以实现对源码的完全控制&#xff0c;同时不依赖任何第三方平台&#xff0c;…

Linux操作系统 4.Linux实用操作

一、各类小技巧&#xff08;快捷键&#xff09; 1.CTRL C 强制停止 1.Linux某些程序的运行&#xff0c;如果想要强行停止它&#xff0c;可以使用ctrlc 2.命令输入错误&#xff0c;也可以通过快捷键ctrl c,退出当前输入&#xff0c;重新输入&#xff0c;或者ctrlc跳过当前这…

react redux的学习,单个reducer

redux系列文章目录 一 什么redux&#xff1f; redux是一个专门用于做状态管理的JS库(不是react插件库)。它可以用在react, angular, vue等项目中, 但基本与react配合使用。集中式管理react应用中多个组件共享的状 简单来说&#xff0c;就是存储页面的状态值的一个库&#xf…

PCI与PCIe接口的通信架构是主从模式吗?

PCI&#xff08;Peripheral Component Interconnect&#xff09;总线在通信架构上本质是主从模式&#xff0c;但其具体实现和角色分配在不同版本&#xff08;如传统PCI与PCI Express&#xff09;中存在差异。以下是详细分析&#xff1a; 传统PCI总线的主从模式 (1) 基本架构 主…

java项目挂机自动重启操作指南

前段时间有个伙伴问我&#xff0c;java项目挂机怎么自动重启。。。。。。今天就写一个 .sh脚本来实现应用挂机的自动重启功能 #!/bin/bash # 查询mita的进程个数 countps -ef | grep mita.jar | grep -v "grep" | wc -l # echo $count nowtimedate "%Y-%m-%d %H…

开放最短路径优先 - OSPF【LSA详细】

目录 LSA的头部结构 LSA类型 LSA数据包 LSA的主要作用是传递路由信息。 LSA的头部结构 共占20个字节&#xff0c;不同类型的LSA头部字段部分都是相同的。 链路状态老化时间(Link-State Age) 2个字节。指示该条LSA的老化时间&#xff0c;即它存在了多长时间&#xff0c;单位…

SpringBoot+Spring+MyBatis相关知识点

目录 一、相关概念 1.spring框架 2.springcloud 3.SpringBoot项目 4.注解 5.SpringBoot的文件结构 6.启动类原理 二、相关操作 1.Jar方式打包 2.自定义返回的业务状态码 3.Jackson 4.加载配置文件 5.异常处理 三、优化配置 1.简化sql语句 2.查询操作 复杂查询 一…

《双影奇境》手机版上线?ToDesk用跨平台技术实现「全设备云电脑3A游戏」

《双影奇境》是由Hazelight Studios研发发行的一款双人合作冒险类游戏&#xff0c;玩家们在游戏中将扮演米欧和佐伊两位风格迥异的女作家&#xff0c;剧情讲述的是她们被骗进入一台意在窃取创意的机器后便陷入了自己创作的故事之中&#xff0c;并且必须相互依靠&#xff0c;努力…

【教程】Windows下 Xshell 连接跳板机和开发机

需求 使用远程连接工具 Xshell 连接跳板机&#xff0c;再从跳板机连接开发机&#xff0c;用户登陆方式为使用密钥。 方法 首先&#xff0c;建立一个会话&#xff0c;用于配置跳板机信息和开发机转跳信息&#xff1a; 在【连接】页面&#xff0c;给跳板机取个名字&#xff0c…

如何快速入门物联网单片机开发?

背景 物联网单片机硬件开发涉及多个阶段&#xff0c;元器件是否“自己设计”取决于具体需求。以下是详细解答和学习方案&#xff1a; 一、元器件是否自己设计&#xff1f; 通用元器件&#xff1a; 大多数情况下&#xff0c;开发者直接使用现成的标准化元器件&#xff08;如电阻…

每日一题(小白)模拟娱乐篇11

由题可知就是要求计算一个数字&#xff0c;可以整除10进制的每一位&#xff0c;亦可以整除8进制和16进制的每一位。要求找出第2023个能够在三个进制下同时被10进制整除的数字。 Java中已经封装了进制转换的方法&#xff0c;以下是一些常用的转换方法&#xff1a;&#x1f447;…

阿里巴巴langengine二次开发大模型平台

阿里巴巴LangEngine开源了&#xff01;支撑亿级网关规模的高可用Java原生AI应用开发框架 - Leepy - 博客园 阿里国际AI应用搭建平台建设之路(上) - 框架篇 基于java二次开发 目前Spring ai、spring ai alibaba 都是java版本的二次基础能力 重要的是前端工作流 如何与 服务端的…

MINIQMT学习课程Day8

获取qmt账号的资金账号后&#xff0c;我们进入下一步&#xff0c;如何获得当前账号的持仓情况 还是之前的步骤&#xff0c;打开qmt&#xff0c;选择独立交易&#xff0c; 之后使用pycharm&#xff0c;编写py文件。 from xtquant import xtdata from xtquant.xttrader import…

在QGIS中将矢量数据导出为JSON

在QGIS中将矢量数据导出为JSON的完整操作指南如下&#xff0c;支持GeoJSON标准格式及自定义配置&#xff1a; 一、标准GeoJSON导出&#xff08;推荐&#xff09; 适用场景&#xff1a;生成符合OGC标准的地理JSON文件&#xff0c;适用于Web地图开发 准备图层 确保目标图层在QG…

Netty——连接超时 与 断开重连

文章目录 1. 处理连接超时和断开重连的原因2. 处理连接超时和断开重连的方法2.1 处理连接超时2.1.1 步骤一&#xff1a;配置连接超时时间2.1.2 步骤二&#xff1a;监听连接结果 2.2 处理断开重连2.2.1 步骤一&#xff1a;监听连接断开事件2.2.2 步骤二&#xff1a;实现重连逻辑…

Redis 与 AI:从缓存到智能搜索的融合之路

Redis 与 AI&#xff1a;从缓存到智能搜索的融合之路 在当今数字化时代&#xff0c;Redis 不仅是一个高性能的缓存系统&#xff0c;更是一个强大的 AI 支持平台。Redis 通过其向量数据库功能和 AI 工具&#xff0c;为现代应用提供了独特的技术优势。 一、Redis 的 AI 能力 &…

LeetCode435 -- 预定会议问题

0. ref 参考自 1. 题目描述 预定会议问题&#xff1a;给定我们一堆区间&#xff0c;区间不能重叠&#xff08; [ 1 , 2 ] [1,2] [1,2] 和 [ 2 , 3 ] [2,3] [2,3] 的 2 2 2 不算重叠&#xff09;&#xff0c;求最多能保留多少个区间&#xff1f; 做法&#xff1a;贪心&#…

leetcode51-N皇后

leetcode 51 思路 本题可以使用回溯算法来解决。回溯算法通过尝试所有可能的解决方案来找到问题的解的算法&#xff0c;当发现当前的选择无法得到有效的解决方案时&#xff0c;就回溯到上一步&#xff0c;尝试其他的选择。对于 N 皇后问题&#xff0c;我们可以逐行放置皇后&…

linux paste 命令

paste 是 Linux 中一个用于水平合并文件内容的命令行工具&#xff0c;它将多个文件的对应行以并行方式拼接&#xff0c;默认用制表符&#xff08;Tab&#xff09;分隔。 1. 基本语法 paste [选项] 文件1 文件2 ... 2. 常用选项 选项说明-d指定拼接后的分隔符&#xff08;默…