多叉树题目: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,一经查实,立即删除!

相关文章

vue/js总结合集

vuex的五大核心 内容作用映射位置调用其它state设置状态mapStatecomputedgetters获取内容mapGetterscomputed计算数据后返回mutations修改数据mapMutationsmethodscommit可以异步&#xff08;不建议&#xff09;不利于调试actions异步操作mapActionsmethodsdispatchmodules模块…

Docker 中安装 Redis

要在 Docker 中安装 Redis&#xff0c;你可以按照以下步骤进行操作&#xff1a; 拉取 Redis 镜像&#xff1a;在命令行中执行以下命令&#xff0c;从 Docker Hub 上拉取 Redis 镜像&#xff1a; docker pull redis 运行 Redis 容器&#xff1a;执行以下命令来在 Docker 中运行…

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

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

蓝桥杯单片机快速开发笔记——特训1 LED闪烁和数码管同步显示

一、示例题目&#xff1a; 在CT107D单片机综合训练平台上&#xff0c;通过I/O模式编写代码&#xff0c;实现以下功能&#xff1a; 系统上电后&#xff0c;初始状态为关闭蜂鸣器、继电器、全部指示灯和数码管&#xff0c;然后进入循环&#xff0c;实现灯光闪烁和数码管计数。数…

代码随想录Day32

Day 32 贪心算法 Part03 今日任务 1005.K次取反后最大化的数组和 加油站 分发糖果 代码实现 1005.K次取反后最大化的数组和 这题有点思路&#xff0c;和题解也差不多&#xff0c;但是没完全通&#xff0c;感觉很复杂&#xff0c;无法下手 public int largestSumAfterKNeg…

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;创建出…

typeScript3(数组类型)

类型[ ] let arr: number[] [1,2,3] //数字类型的数组 let arr:string[] [1, 2] //字符串类型的数组 let arr:any[] [1,2,false] //任意类型的数组 数组泛型 Array<类型> let arr:Array<number> [1,2,3] 接口表示数组 //只要索引的类型是数字时&#xff0c;那…

Java基础---IO流习题

使用对象IO流简单练习一个图书管理系统 Book类&#xff08;书类&#xff09; package day2024_03_21.pojo;import java.io.Serializable;public class Book implements Serializable {private static final long serialVersionUID 1L;private Integer BookId;private Stri…

import * as的使用

import * as 是将一个模块的所有导出内容作为一个命名空间对象导入到当前模块中&#xff0c;其中 * 表示导入该模块中的所有导出内容&#xff0c;而 as 则用于指定导入的命名空间对象的名称。 例如&#xff1a;在 formatter 文件中有两个方法导出 const a () > {console.…

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

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

亚马逊广告八大打法,新手卖家须知

在亚马逊平台上&#xff0c;商家们可以利用各种广告产品来推广他们的商品和品牌。今天给大家分享亚马逊上常见的八种广告打法&#xff01; 亚马逊广告八大打法 一、Coupon白帽刷广告法 1️⃣ 发布大额优惠券&#xff1a;在产品详情页提供引人注意的大额优惠券&#xff08;打折幅…

图像分类的实战案例

图像分类是计算机视觉领域的一个基本任务&#xff0c;它在许多实际应用中都有广泛的应用。以下是一些图像分类的实战案例&#xff1a; 人脸识别&#xff1a; 应用&#xff1a;安全监控、身份验证、社交媒体面部标记。实例&#xff1a;使用深度学习模型识别和验证图像中的人脸&…

前端理论总结(css3)——css动画与js动画区别 // 选择器/优先级

一、 css动画与js动画区别 1&#xff1a;js是逐帧动画&#xff0c;css是补间动画。 2&#xff1a;js动画控制能力很强可以在动画播放过程中对动画进行控制&#xff1a;开始、暂停、回放、终止、取消都是可以做到的 3&#xff1a;js动画使用CPU运算&#xff0c;会阻…

真机笔记(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模块的…

Rust 语言中 Vec 的元素的删除方法

在 Rust 中&#xff0c;Vec&#xff08;向量&#xff09;提供了多种删除元素的方法。以下是一些常用的删除方法&#xff1a; remove: 这是最常用的删除方法&#xff0c;它接受一个索引作为参数&#xff0c;并移除该索引处的元素&#xff0c;同时返回被移除的元素。所有后面的元…

Java贪心算法(含面试大厂题和源码)

贪心算法是一种在每一步选择中都采取在当前状态下最好或最优&#xff08;即最有利&#xff09;的选择&#xff0c;从而希望导致结果是全局最好或最优的算法策略。贪心算法解决问题的过程中&#xff0c;每一步都做出一个看似最优的决定&#xff0c;它永远不会回溯&#xff0c;这…

洛谷刷题 | B3623 枚举排列

枚举排列 题目描述 今有 n n n 名学生&#xff0c;要从中选出 k k k 人排成一列拍照。 请按字典序输出所有可能的排列方式。 输入格式 仅一行&#xff0c;两个正整数 n , k n, k n,k。 输出格式 若干行&#xff0c;每行 k k k 个正整数&#xff0c;表示一种可能的队…