想要精通算法和SQL的成长之路 - 二叉树的序列化和反序列化问题

想要精通算法和SQL的成长之路 - 二叉树的序列化和反序列化问题

  • 前言
  • 一. 二叉树的层序遍历(BFS)
  • 二. 二叉树的序列化与反序列化
    • 2.1 序列化操作
    • 2.2 反序列化操作

前言

想要精通算法和SQL的成长之路 - 系列导航

一. 二叉树的层序遍历(BFS)

二叉树的层序遍历
在这里插入图片描述
像这种从上至下并且按层打印的,可以称之为二叉树的广度优先搜索(BFS。而这类算法往往借助队列的一个先入先出特性来实现。

那么有这么几个步骤:
1.特殊处理还有初始化动作。

List<List<Integer>> res = new ArrayList<>();
// 树为空,返回空数组
if (root == null) {return res;
}
// 初始化队列
LinkedList<TreeNode> queue = new LinkedList<>();
queue.add(root);

2.BFS循环:

while (!queue.isEmpty()) {// 该层的打印结果ArrayList<Integer> tmp = new ArrayList<>();// 将当前层(队列内的元素)全部打印for (int i = queue.size(); i > 0; i--) {// 队首先出TreeNode node = queue.poll();tmp.add(node.val);// 从左往右添加元素(先进先出)if (node.left != null) {tmp.add(node.left.val);}if (node.right != null) {tmp.add(node.right.val);}}// 当前层的遍历结果加入到最终结果集中res.add(tmp);
}

最终完整代码如下:

public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> res = new ArrayList<>();// 树为空,返回空数组if (root == null) {return res;}// 初始化队列LinkedList<TreeNode> queue = new LinkedList<>();queue.add(root);while (!queue.isEmpty()) {// 该层的打印结果ArrayList<Integer> tmp = new ArrayList<>();// 将当前层(队列内的元素)全部打印for (int i = queue.size(); i > 0; i--) {// 队首先出TreeNode node = queue.poll();tmp.add(node.val);// 从左往右添加元素(先进先出)if (node.left != null) {tmp.add(node.left.val);}if (node.right != null) {tmp.add(node.right.val);}}// 当前层的遍历结果加入到最终结果集中res.add(tmp);}return res;
}

二. 二叉树的序列化与反序列化

原题链接
在这里插入图片描述
从题目来看,序列化的操作就是:从上往下,从左往右的一个层级遍历。那么在做这个题目之前,我们可以看下这个题目:

那么我们回归本题,本题和1.1小节的题目有啥不同?

  • 如果是空节点,我们要输出null
  • 我们还要根据序列化的结果,反序列化回一颗二叉树。

我们依旧可以使用队列来解决。

2.1 序列化操作

首先,特判以及队列的初始化操作:

if (root == null) {return "[]";
}
StringBuilder res = new StringBuilder("[");
LinkedList<TreeNode> queue = new LinkedList<>();
queue.add(root);

顺带提一嘴,希望大家养成良好的编码习惯,关于字符串的equal比较,常量放在前面,变量放后面,避免不必要的空指针。

BFS递归操作:

while (!queue.isEmpty()) {// 队列先进先出,从队首开始出队for (int i = queue.size(); i > 0; i--) {TreeNode node = queue.poll();// 只不过这里多加了一个判断而已,如果是空节点,我们添加nullif (node == null) {res.append("null,");continue;}// 否则,非空,添加当前节点的值res.append(node.val + ",");// 由于上面已经加了null的判断了,这里直接按顺序先加左节点,再加右节点即可。queue.add(node.left);queue.add(node.right);}
}

最后就是收尾工作:我们对于结尾的值,要把多余的逗号去除。

// 删除最后一个多余的逗号
res.deleteCharAt(res.length() - 1);
res.append("]");
return res.toString();

最终完整代码如下:

public String serialize(TreeNode root) {if (root == null) {return "[]";}StringBuilder res = new StringBuilder("[");LinkedList<TreeNode> queue = new LinkedList<>();queue.add(root);while (!queue.isEmpty()) {// 队列先进先出,从队首开始出队for (int i = queue.size(); i > 0; i--) {TreeNode node = queue.poll();// 只不过这里多加了一个判断而已,如果是空节点,我们添加nullif (node == null) {res.append("null,");continue;}// 否则,非空,添加当前节点的值res.append(node.val + ",");// 由于上面已经加了null的判断了,这里直接按顺序先加左节点,再加右节点即可。queue.add(node.left);queue.add(node.right);}}// 删除最后一个多余的逗号res.deleteCharAt(res.length() - 1);res.append("]");return res.toString();
}

2.2 反序列化操作

同样地,特判以及队列的初始化操作:

if ("[]".equals(data)) {return null;
}
// 各个节点的值
String[] vals = data.substring(1, data.length() - 1).split(",");
// 第一个值必定是根节点(从上往下的特性)
TreeNode root = new TreeNode(Integer.parseInt(vals[0]));
LinkedList<TreeNode> queue = new LinkedList<TreeNode>() {{add(root);
}};

BFS操作:

int index = 1;
while (!queue.isEmpty()) {TreeNode node = queue.poll();// 处理左节点if (!"null".equals(vals[index])) {node.left = new TreeNode(Integer.parseInt(vals[index]));queue.add(node.left);}// 这里不管怎样都是要往后移动一位,如果是null,我们node.left就默认是null了。index++;if (!"null".equals(vals[index])) {node.right = new TreeNode(Integer.parseInt(vals[index]));queue.add(node.right);}index++;
}

完整代码:

public TreeNode deserialize(String data) {if ("[]".equals(data)) {return null;}String[] vals = data.substring(1, data.length() - 1).split(",");TreeNode root = new TreeNode(Integer.parseInt(vals[0]));LinkedList<TreeNode> queue = new LinkedList<TreeNode>() {{add(root);}};int index = 1;while (!queue.isEmpty()) {TreeNode node = queue.poll();// 处理左节点if (!"null".equals(vals[index])) {node.left = new TreeNode(Integer.parseInt(vals[index]));queue.add(node.left);}// 这里不管怎样都是要往后移动一位,如果是null,我们node.left就默认是null了。index++;if (!"null".equals(vals[index])) {node.right = new TreeNode(Integer.parseInt(vals[index]));queue.add(node.right);}index++;}return root;
}

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

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

相关文章

RabbitMQ-主题模式

接上文 RabbitMQ-发布订阅模式和路由模式 1 主题模式 #通配符 代表0个或多个。*通配符 代表 1个或多个 进行测试&#xff0c;修改配置文件 Configuration public class RabbitConfiguration {Bean("topicExchange") //这里使用预置的Topic类型交换机public Exchan…

JMETER自适应高分辨率的显示器

系列文章目录 历史文章 每天15分钟JMeter入门篇&#xff08;一&#xff09;&#xff1a;Hello JMeter 每天15分钟JMeter入门篇&#xff08;二&#xff09;&#xff1a;使用JMeter实现并发测试 每天15分钟JMeter入门篇&#xff08;三&#xff09;&#xff1a;认识JMeter的逻辑控…

nginx下载与安装教程

文章目录 nginx简介nginx的主要应用场景nginx开源项目的源码结构 使用centos7安装nginx检查centos版本号和linux内核版本检查是否安装gcc、pcre、zlib、openssl等依赖 安装nginx启动nginx停止nginx重启nginx nginx简介 nginx是一款业内流行、功能强大的web服务器。 高性能&…

FFmpeg 命令:从入门到精通 | ffplay 播放控制选项

FFmpeg 命令&#xff1a;从入门到精通 | ffplay 播放控制选项 FFmpeg 命令&#xff1a;从入门到精通 | ffplay 播放控制选项选项表格图片 FFmpeg 命令&#xff1a;从入门到精通 | ffplay 播放控制选项 选项表格 项目说明Q&#xff0c;Esc退出播放F&#xff0c;鼠标左键双击全…

[React] React高阶组件(HOC)

文章目录 1.Hoc介绍2.几种包装强化组件的方式2.1 mixin模式2.2 extends继承模式2.3 HOC模式2.4 自定义hooks模式 3.高阶组件产生初衷4.高阶组件使用和编写结构4.1 装饰器模式和函数包裹模式4.2 嵌套HOC 5.两种不同的高阶组件5.1 正向的属性代理5.2 反向的继承 6.如何编写高阶组…

【C语言】函数的定义、传参与调用(二)

&#x1f497;个人主页&#x1f497; ⭐个人专栏——C语言初步学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 导读&#xff1a; 1. 函数的嵌套调用 1.1 什么是嵌套调用 1.2 基础实现 1.3 调用流程解析 2. 函数的链式访问 2.1 …

CCF CSP认证 历年题目自练Day21

题目一 试题编号&#xff1a; 201909-1 试题名称&#xff1a; 小明种苹果 时间限制&#xff1a; 2.0s 内存限制&#xff1a; 512.0MB 题目分析&#xff08;个人理解&#xff09; 先看输入&#xff0c;第一行输入苹果的棵树n和每一次掉的苹果数m还是先如何存的问题&#xf…

小谈设计模式(16)—抽象工厂模式

小谈设计模式&#xff08;16&#xff09;—抽象工厂模式 专栏介绍专栏地址专栏介绍 抽象工厂模式结构抽象工厂&#xff08;AbstractFactory&#xff09;具体工厂&#xff08;ConcreteFactory&#xff09;抽象产品&#xff08;AbstractProduct&#xff09;具体产品&#xff08;C…

2023年10月4日

服务器 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//实例化一个服务器server new QTcpServer(this);//此时&#xff0c;服务器已经成功进入监听状态&…

ubuntu22.04 x11窗口环境手势控制

ubuntu22.04 x11窗口环境手势控制 ubuntu x11窗口环境的手势控制并不优秀&#xff0c;我们可以使用touchegg去代替 这个配置过程非常简单&#xff0c;并且可以很容易在一定范围内达到你想到的效果&#xff0c;类比mac的手势控制 关于安装 首先添加源&#xff0c;并安装 sud…

进程调度的时机,切换与过程以及方式

1.进程调度的时机 进程调度&#xff08;低级调度〉&#xff0c;就是按照某种算法从就绪队列中选择一个进程为其分配处理机。 1.需要进行进程调度与切换的情况 1.当前运行的进程主动放弃处理机 进程正常终止运行过程中发生异常而终止进程主动请求阻塞&#xff08;如等待l/O)…

电脑通过串口助手和51单片机串口通讯

今天有时间把电脑和51单片机之间的串口通讯搞定了&#xff0c;电脑发送的串口数据&#xff0c;单片机能够正常接收并显示到oled屏幕上&#xff0c;特此记录一下&#xff0c;防止后面自己忘记了怎么搞得了。 先来两个图片看看结果吧&#xff01; 下面是串口3.c的文件全部内容&a…

OpenGLES:绘制一个混色旋转的3D圆锥

效果展示&#xff1a; 本篇博文总共会实现两种混色旋转的3D圆锥&#xff1a; 一.圆锥解析 1.1 对圆锥的拆解 上一篇博文讲解了绘制圆柱体&#xff0c;这一篇讲解绘制一个彩色旋转的圆锥 在绘制圆柱体时提到过&#xff0c;关键点是先将圆柱进行拆解&#xff0c;便于创建出顶…

计算机网络(五):运输层

参考引用 计算机网络微课堂-湖科大教书匠计算机网络&#xff08;第7版&#xff09;-谢希仁 1. 运输层概述 之前所介绍的计算机网络体系结构中的物理层、数据链路层以及网络层它们共同解决了将主机通过异构网络互联起来所面临的问题&#xff0c;实现了主机到主机的通信&#xff…

Ubuntu安装samba服务器

为了window系统下能够像访问本地目录一样访问ubuntu系统下的目录&#xff0c;这里我通过安装samba服务器&#xff0c;将ubuntu系统的文件目录通过网络挂载的方式共享出来&#xff0c;以便在window下就能够对ubuntu系统的文件进行读写等访问操作&#xff0c;这里记录一下samba服…

ESLint自动修复代码规范错误

基于 vscode 插件 ESLint 高亮错误&#xff0c;并通过配置 自动 帮助我们修复错误 在设置中 settings.json添加这段代码就自动修复错误 // 当保存的时候&#xff0c;eslint自动帮我们修复错误 "editor.codeActionsOnSave": { "source.fixAll": true }, /…

如何使用 AI与人工智能的定义、研究价值、发展阶段

目录 一、什么是人工智能 二、人工智能的研究价值 三、人工智能的发展阶段 一、什么是人工智能 人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;是一门研究如何使计算机能够模拟和执行人类智能活动的科学与技术。人工智能旨在开发智能代理&…

Kaggle - LLM Science Exam上:赛事概述、数据收集、BERT Baseline

文章目录 一、赛事概述1.1 OpenBookQA Dataset1.2 比赛背景1.3 评估方法和代码要求1.4 比赛数据集1.5 优秀notebook 二、BERT Baseline2.1 数据预处理2.2 定义data_collator2.3 加载模型&#xff0c;配置trainer并训练2.4 预测结果并提交2.5 相关优化 前言&#xff1a;国庆期间…

常见web信息泄露

一、源码(备份文件)泄露 1、git泄露 Git是一个开源的分布式版本控制系统&#xff0c;在执行git init初始化目录的时候&#xff0c;会在当前目录下自动创建一个.git目录&#xff0c;用来记录代码的变更记录等。发布代码的时候&#xff0c;如果没有把.git这个目录删除&#xff…

前后端通信到底是怎样一个过程

前后端通信是怎样 前言&#xff1a;Http协议 超文本传输协议 规定&#xff1a;每一次前后端通信&#xff0c;前端需要主动向后端发出请求&#xff0c;后端接收到前端的请求后&#xff0c;可以给出响应 1、Http报文 浏览器向服务器发送请求时&#xff0c;请求本身就是信息&…