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

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
      • 进阶
  • 解法一
    • 思路和算法
    • 代码
    • 复杂度分析
  • 解法二
    • 思路和算法
    • 代码
    • 复杂度分析
  • 解法三
    • 思路和算法
    • 代码
    • 复杂度分析

题目

标题和出处

标题:N 叉树的前序遍历

出处:589. N 叉树的前序遍历

难度

3 级

题目描述

要求

给定一个 N 叉树的根结点 root \texttt{root} root,返回其结点值的前序遍历。

N 叉树在输入中按层序遍历序列化表示,每组子结点由空值 null \texttt{null} null 分隔(请参见示例)。

示例

示例 1:

示例 1

输入: root = [1,null,3,2,4,null,5,6] \texttt{root = [1,null,3,2,4,null,5,6]} root = [1,null,3,2,4,null,5,6]
输出: [1,3,5,6,2,4] \texttt{[1,3,5,6,2,4]} [1,3,5,6,2,4]

示例 2:

示例 2

输入: root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14] \texttt{root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]} root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
输出: [1,2,3,6,7,11,14,4,8,12,5,9,13,10] \texttt{[1,2,3,6,7,11,14,4,8,12,5,9,13,10]} [1,2,3,6,7,11,14,4,8,12,5,9,13,10]

数据范围

  • 树中结点数目在范围 [0, 10 4 ] \texttt{[0, 10}^\texttt{4}\texttt{]} [0, 104]
  • 0 ≤ Node.val ≤ 10 4 \texttt{0} \le \texttt{Node.val} \le \texttt{10}^\texttt{4} 0Node.val104
  • N 叉树的高度小于或等于 1000 \texttt{1000} 1000

进阶

递归解法很简单,你可以使用迭代解法完成吗?

解法一

思路和算法

N 叉树的前序遍历的方法为:首先遍历根结点,然后按照从左到右的顺序依次遍历每个子树,对于每个子树使用同样的方法遍历。由于遍历过程具有递归的性质,因此可以使用递归的方法实现 N 叉树的前序遍历。

递归的终止条件是当前结点为空。对于非终止条件,递归的做法如下。

  1. 将当前结点的结点值加入前序遍历序列。

  2. 按照从左到右的顺序,依次对当前结点的每个子树调用递归。

遍历结束之后即可得到前序遍历序列。

代码

class Solution {List<Integer> traversal = new ArrayList<Integer>();public List<Integer> preorder(Node root) {preorderVisit(root);return traversal;}public void preorderVisit(Node node) {if (node == null) {return;}traversal.add(node.val);List<Node> children = node.children;for (Node child : children) {preorderVisit(child);}}
}

复杂度分析

  • 时间复杂度: O ( m ) O(m) O(m),其中 m m m 是 N 叉树的结点数。每个结点都被访问一次。

  • 空间复杂度: O ( m ) O(m) O(m),其中 m m m 是 N 叉树的结点数。空间复杂度主要是递归调用的栈空间,取决于 N 叉树的高度,最坏情况下 N 叉树的高度是 O ( m ) O(m) O(m)

解法二

思路和算法

使用迭代的方法实现 N 叉树的前序遍历,则需要使用栈存储结点。

由于前序遍历的过程中,对于同一个结点的子树的访问顺序是从左到右,因此当访问一个结点之后,将该结点的所有子结点按照从右到左的顺序依次入栈,则利用栈的后进先出的特点,子结点的出栈顺序为从左到右的顺序,和前序遍历的顺序相同。

当树为空时,前序遍历列表为空。当树不为空时,首先将根结点入栈,然后按照如下操作执行前序遍历。

  1. 将一个结点出栈,将当前结点的结点值加入前序遍历序列。

  2. 将当前结点的所有子结点按照从右到左的顺序依次入栈。

  3. 重复上述操作,直到栈为空时,前序遍历结束。

代码

class Solution {public List<Integer> preorder(Node root) {List<Integer> traversal = new ArrayList<Integer>();if (root == null) {return traversal;}Deque<Node> stack = new ArrayDeque<Node>();stack.push(root);while (!stack.isEmpty()) {Node node = stack.pop();traversal.add(node.val);List<Node> children = node.children;for (int i = children.size() - 1; i >= 0; i--) {stack.push(children.get(i));}}return traversal;}
}

复杂度分析

  • 时间复杂度: O ( m ) O(m) O(m),其中 m m m 是 N 叉树的结点数。每个结点都被访问一次。

  • 空间复杂度: O ( m ) O(m) O(m),其中 m m m 是 N 叉树的结点数。空间复杂度主要是栈空间,栈内元素个数不超过 m m m

解法三

思路和算法

另一种使用迭代实现 N 叉树的前序遍历的方法是使用哈希表存储每个结点的已访问的最后一个子结点下标(以下简称「子结点下标」),而不是将子结点按照从右到左的顺序入栈,同样需要使用栈存储结点。

从根结点开始遍历,遍历的终止条件是栈为空且当前结点为空。遍历的做法如下。

  1. 如果当前结点不为空,则将当前结点的结点值加入前序遍历序列,将当前结点入栈。如果当前结点不是叶结点,则将当前结点的子结点下标设为 0 0 0,将当前结点移动到其子结点中的最左侧的子结点,重复上述操作。如果当前结点是叶结点,则在执行上述操作之后将当前结点设为空。

  2. 将栈顶结点的子结点下标加 1 1 1 记为新下标,则新下标为下一个待访问的子结点下标。如果新下标在子结点下标范围内则用新下标更新栈顶结点的子结点下标,将当前结点设为下一个待访问的结点;如果新下标不在子结点下标范围内则将栈顶结点出栈,将当前结点设为空。

  3. 重复上述操作,直到达到遍历的终止条件。

代码

class Solution {public List<Integer> preorder(Node root) {List<Integer> traversal = new ArrayList<Integer>();if (root == null) {return traversal;}Map<Node, Integer> map = new HashMap<Node, Integer>();Deque<Node> stack = new ArrayDeque<Node>();Node node = root;while (!stack.isEmpty() || node != null) {while (node != null) {traversal.add(node.val);stack.push(node);List<Node> children = node.children;if (!children.isEmpty()) {map.put(node, 0);node = children.get(0);} else {node = null;}}node = stack.peek();int index = map.getOrDefault(node, -1) + 1;List<Node> children = node.children;if (index < children.size()) {map.put(node, index);node = children.get(index);} else {stack.pop();map.remove(node);node = null;}}return traversal;}
}

复杂度分析

  • 时间复杂度: O ( m ) O(m) O(m),其中 m m m 是 N 叉树的结点数。每个结点都被访问一次。

  • 空间复杂度: O ( m ) O(m) O(m),其中 m m m 是 N 叉树的结点数。空间复杂度主要是哈希表和栈空间,哈希表和栈内元素个数都不超过 m m m

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

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

相关文章

一文速通自监督学习(Self-supervised Learning):教机器自我探索的艺术

一文速通自监督学习&#xff08;Self-supervised Learning&#xff09;&#xff1a;教机器自我探索的艺术 前言自监督学习是什么&#xff1f;自监督学习的魔力常见的自监督学习方法1. 对比学习2. 预测缺失部分3. 旋转识别4. 时间顺序预测 结语 &#x1f308;你好呀&#xff01;…

Docker新手攻略:编辑Dockerfile、构建镜像、启动容器全攻略

万能dockerfile编写模板文件 FROM openjdk:11.0 as builder WORKDIR application ARG JAR_FILEtarget/*.jar COPY ${JAR_FILE} application.jar RUN java -Djarmodelayertools -jar application.jar extractFROM openjdk:11.0 WORKDIR application COPY --frombuilder applica…

Springboot项目结构

1. 一个正常的企业项目里一种通用的项目结构和代码层级划分的指导意见&#xff1a; 一般分为如下几层&#xff1a; 开放接口层 终端显示层 Web 层 Service 层 Manager 层 DAO 层 外部接口或第三方平台 2. 以当下非常火热的Spring Boot典型项目结构为例&#xff0c;创建出…

代码随想录算法训练营第三十四天 |1005. K 次取反后最大化的数组和 、134. 加油站、135. 分发糖果

代码随想录算法训练营第三十四天 |1005. K 次取反后最大化的数组和 、134. 加油站、135. 分发糖果 1005. K 次取反后最大化的数组和题目解法 134. 加油站题目解法 135. 分发糖果题目解法 感悟 1005. K 次取反后最大化的数组和 题目 解法 考虑绝对值 class Solution { public…

真机笔记(3) 真机需求讲解

目录 拓扑分析&#xff1a; 设计理念&#xff1a; 1. 生产区交换需求&#xff1a; 2. 生产区交换需求&#xff1a; 3. 服务器区交换需求&#xff1a; 4. 路由设计 5. 地址规划&#xff1a; 拓扑分析&#xff1a; 蓝色&#xff1a;网线 红色&#xff1a;多模光纤 黄色&am…

【SpringBoot框架篇】37.使用gRPC实现远程服务调用

文章目录 RPC简介gPRC简介protobuf1.文件编写规范2.字段类型3.定义服务(Services) 在Spring Boot中使用grpc1.父工程pom配置2.grpc-api模块2.1.pom配置2.2.proto文件编写2.3.把proto文件编译成class文件 3.grpc-server模块3.1.pom文件和application.yaml3.2.实现grpc-api模块的…

2-Flume之Sink与Channel

Flume Sink HDFS Sink 将数据写到HDFS上。数据以文件形式落地到HDFS上&#xff0c;文件名默认是以FlumeData开头&#xff0c;可以通过hdfs.filePrefix来修改 HDFS Sink默认每隔30s会滚动一次生成一个文件&#xff0c;因此会导致在HDFS上生成大量的小文件&#xff0c;实际过程…

使用git下载github/gitee仓库部分或单个文件的方法

前言 有些时候在github或者gitee仓库中我们只需要下载整个项目中的我门需要的那一部分文件夹或文件就行了&#xff0c;不需要下载所有的项目。这样可以节省很多流量和时间 步骤 1.建立一个新的 git 本地仓库 这里我在D:\test中初始化 命令&#xff1a; git init2.在本地仓…

Istio 部署 Spring Coud 微服务应用

Istio 服务部署 这篇文章讲述如何将 Java Spring Cloud 微服务应用部署到 Istio mesh 中。 准备基础环境 使用 Kind 模拟 kubernetes 环境。文章参考&#xff1a;https://blog.csdn.net/qq_52397471/article/details/135715485 在 kubernetes cluster 中安装 Istio 创建一…

Excel双击单元格后弹窗输入日期

Step1. 在VBE界面新建一个窗体(Userform1),在窗体的工具箱的空白处右键,选中添加附件,勾选Calendar control 8.0,即可完成日历的添加。 PS:遗憾的是, Office 64 位没有官方的日期选择器控件。唯一的解决方案是使用Excel 的第三方日历。 参考链接:How to insert calen…

电路笔记 :灯光画 JLC 嘉立创EDA+PCB打样(笔记)

项目介绍 PCB板灯光画(可行性验证)&#xff0c;PCB灯光画无论是电路原理还是焊接都非常简单&#xff0c;所有元器件均采用0805及体积更大的封装&#xff0c;只需要电烙铁和焊锡丝等基础的工具就能制作&#xff0c;新手小白也能轻松复刻&#xff0c;里边还有PCB板实现灯光画效果…

数据交换技术

目录 <线路交换> <报文交换> <分组交换> 1.数据报分组交换 2.虚电路分组交换 计算机网络是以数据交换为目的的技术&#xff0c;从交换技术的发展过程来看&#xff0c;主要经历了线 路交换、报文交换、分组交换的过程。 <线路交换> 线路交换又称为…

vue3+threejs新手从零开发卡牌游戏(十):创建己方战域

首先在game目录下创建site文件夹&#xff0c;用来存放战域相关代码&#xff1a; 这里思考下如何创建战域&#xff0c;我的想法是添加一个平面&#xff0c;将己方战域和对方战域都添加进这个平面中&#xff0c;所以首先我们先添加一个战域plane&#xff0c;site/index.vue代码如…

[蓝桥杯 2020 省 AB1] 网络分析

一开始写的暴力合并 卡n^2过的不是正解 看正解是类似 虚拟点树形DP的思路 很巧妙 记录一下 #include<bits/stdc.h> using namespace std; using ll long long; using pii pair<int,int>; #define int long long const int N 3e510; const int inf 0x3f3f3f3f; …

【RPG Maker MV 仿新仙剑 战斗场景UI (八)】

RPG Maker MV 仿新仙剑 战斗场景UI 八 状态及装备场景代码效果 状态及装备场景 本计划在战斗场景中直接制作的&#xff0c;但考虑到在战斗场景中加入太多的窗口这不太合适&#xff0c;操作也繁琐&#xff0c;因此直接使用其他场景。 代码 Pal_Window_EquipStatus.prototype.…

Word邮件合并

Word邮件合并功能可以解决在Word中批量填写内容的需求&#xff0c;当需要大量格式相同&#xff0c;只修改少数相关内容时&#xff0c;例如利用Word制作工资条&#xff0c;通知函&#xff0c;奖状等等&#xff0c;同时操作也非常简单灵活。下面通过例子来说明邮件合并的使用方法…

突破距离限制 远程级联测径仪 让您使用更安心!

关键词&#xff1a;在线测径仪,测径仪,远程级联 在现代工业领域&#xff0c;测量的准确性和高效性至关重要。在线测径仪不仅具备了这两项特质&#xff0c;更能进行远程级联&#xff0c;能更快速的为您解决软件系统在使用中遇到的问题。 在线测径仪能做到以下几点 精准测量&am…

过了30岁,要具备翻篇的能力

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 杨绛先生曾经说过&#xff1a; “人生没有彩排&#xff0c;每一天都是现场直播。只有翻篇&#xff0c;才能重新开始。” 一个人如果整天回顾以前&#xff0c;想着自己做的不好的事情&#xff0c;想着曾经遇到的挫折&am…

vue.js制作学习计划表案例

通俗易懂&#xff0c;完成“学习计划表”用于对学习计划进行管理&#xff0c;包括对学习计划进行添加、删除、修改等操作。 一. 初始页面效果展示 二.添加学习计划页面效果展示 三.修改学习计划完成状态的页面效果展示 四.删除学习计划 当学习计划处于“已完成”状态时&…