​LeetCode刷题实战331:验证二叉树的前序序列化

本文解析如何利用栈数据结构解决LeetCode中的二叉树前序序列化验证问题,通过理解槽位概念和栈操作实现有效判断。

算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 !

今天和大家聊的问题叫做 验证二叉树的前序序列化,我们先来看题面:

https://leetcode-cn.com/problems/verify-preorder-serialization-of-a-binary-tree/

示例

示例 1:

输入: "9,3,4,#,#,1,#,#,2,#,6,#,#"
输出: true

示例 2:

输入: "1,#"
输出: false

示例 3:

输入: "9,#,#,1"
输出: false

解题

方法一:栈

我们可以定义一个概念,叫做槽位。一个槽位可以被看作「当前二叉树中正在等待被节点填充」的那些位置。

二叉树的建立也伴随着槽位数量的变化。每当遇到一个节点时:

如果遇到了空节点,则要消耗一个槽位;

如果遇到了非空节点,则除了消耗一个槽位外,还要再补充两个槽位。

此外,还需要将根节点作为特殊情况处理。

我们使用栈来维护槽位的变化。栈中的每个元素,代表了对应节点处剩余槽位的数量,而栈顶元素就对应着下一步可用的槽位数量。当遇到空节点时,仅将栈顶元素减 1;当遇到非空节点时,将栈顶元素减 1 后,再向栈中压入一个 2。无论何时,如果栈顶元素变为 0,就立刻将栈顶弹出。

遍历结束后,若栈为空,说明没有待填充的槽位,因此是一个合法序列;否则若栈不为空,则序列不合法。此外,在遍历的过程中,若槽位数量不足,则序列不合法。

class Solution {
    public boolean isValidSerialization(String preorder) {
        int n = preorder.length();
        int i = 0;
        Deque<Integer> stack = new LinkedList<Integer>();
        stack.push(1);
        while (i < n) {
            if (stack.isEmpty()) {
                return false;
            }
            if (preorder.charAt(i) == ',') {
                i++;
            } else if (preorder.charAt(i) == '#'){
                int top = stack.pop() - 1;
                if (top > 0) {
                    stack.push(top);
                }
                i++;
            } else {
                // 读一个数字
                while (i < n && preorder.charAt(i) != ',') {
                    i++;
                }
                int top = stack.pop() - 1;
                if (top > 0) {
                    stack.push(top);
                }
                stack.push(2);
            }
        }
        return stack.isEmpty();
    }
}

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/verify-preorder-serialization-of-a-binary-tree/solution/yan-zheng-er-cha-shu-de-qian-xu-xu-lie-h-jghn/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

好了,今天的文章就到这里,如果觉得有所收获,请顺手点个在看或者转发吧,你们的支持是我最大的动力 。

上期推文:

LeetCode1-320题汇总,希望对你有点帮助!

LeetCode刷题实战321:拼接最大数

LeetCode刷题实战322:零钱兑换

LeetCode刷题实战323:无向图中连通分量的数目

LeetCode刷题实战324:摆动排序 II

LeetCode刷题实战325:和等于 k 的最长子数组长度

LeetCode刷题实战326:3的幂

LeetCode刷题实战327:区间和的个数

LeetCode刷题实战328:奇偶链表

LeetCode刷题实战329:矩阵中的最长递增路径

LeetCode刷题实战330:按要求补齐数组

【事件触发一致性】研究多智能体网络如何通过分布式事件驱动控制实现有限时间内的共识(Matlab代码实现)内容概要:本文围绕多智能体网络中的事件触发一致性问,研究如何通过分布式事件驱动控制实现有限时间内的共识,并提供了相应的Matlab代码实现方案。文中探讨了事件触发机制在降低通信负担、提升系统效率方面的优势,重点分析了多智能体系统在有限时间收敛的一致性控制策略,涉及系统模型构建、触发条件设计、稳定性与收敛性分析等核心技术环节。此外,文档还展示了该技术在航空航天、电力系统、机器人协同、无人机编队等多个前沿领域的潜在应用,体现了其跨学科的研究价值和工程实用性。; 适合人群:具备一定控制理论基础和Matlab编程能力的研究生、科研人员及从事自动、智能系统、多智能体协同控制等相关领域的工程技术人员。; 使用场景及目标:①用于理解和实现多智能体系统在有限时间内达成一致的分布式控制方法;②为事件触发控制、分布式优、协同控制等课提供算法设计与仿真验证的技术参考;③支撑科研项目开发、学术论文复现及工程原型系统搭建; 阅读建议:建议结合文中提供的Matlab代码进行实践操作,重点关注事件触发条件的设计逻辑与系统收敛性证明之间的关系,同时可延伸至其他应用场景进行二次开发与性能优
【四旋翼无人机】具备螺旋桨倾斜机构的全驱动四旋翼无人机:建模与控制研究(Matlab代码、Simulink仿真实现)内容概要:本文围绕具备螺旋桨倾斜机构的全驱动四旋翼无人机展开,重点研究其动力学建模与控制系统设计。通过Matlab代码与Simulink仿真实现,详细阐述了该类无人机的运动学与动力学模型构建过程,分析了螺旋桨倾斜机构如何提升无人机的全向机动能力与姿态控制性能,并设计相应的控制策略以实现稳定飞行与精确轨迹跟踪。文中涵盖了从系统建模、控制器设计到仿真验证的完整流程,突出了全驱动结构相较于传统四旋翼在欠驱动问上的优势。; 适合人群:具备一定控制理论基础和Matlab/Simulink使用经验的自动、航空航天及相关专业的研究生、科研人员或无人机开发工程师。; 使用场景及目标:①学习全驱动四旋翼无人机的动力学建模方法;②掌握基于Matlab/Simulink的无人机控制系统设计与仿真技术;③深入理解螺旋桨倾斜机构对飞行性能的影响及其控制实现;④为相关课研究或工程开发提供可复现的技术参考与代码支持。; 阅读建议:建议读者结合提供的Matlab代码与Simulink模型,逐步跟进文档中的建模与控制设计步骤,动手实践仿真过程,以加深对全驱动无人机控制原理的理解,并可根据实际需求对模型与控制器进行修改与优
<think>嗯,用户问的是链式存储的二叉树怎么同步到文件。这个问看起来是关于数据结构和文件操作的结合。首先,我需要明确几个概念:链式存储的二叉树是什么样的结构,文件同步的具体需求是什么,用户可能需要什么样的实现方式,比如是文本文件还是二进制文件,是否需要可读性等等。 首先,链式存储的二叉树通常是用节点结构体或类来表示,每个节点包含数据以及左右子节点的指针或引用。这种结构在内存中是动态分配的,节点之间通过指针连接。而将这样的结构同步到文件,就需要将这种非线性的结构转换为线性存储的形式,比如通过某种序列的方法。 接下来要考虑的是同步的方式。常见的序列方法有先序、中序、后序遍历,或者层次遍历。每种遍历方式保存到文件后的恢复方式不同。例如,先序遍历配合标记空节点的方法可以方便地重建二叉树,比如使用特殊符号(如#)表示空节点。这种方法在文本文件中容易实现,但可能会占用较多空间,特别是当树比较稀疏的时候。 另外,用户可能需要考虑存储的效率和恢复的准确性。比如,使用二进制文件可能会更节省空间,但可读性差;而文本文件虽然可读,但处理起来可能需要更多的解析工作。此外,是否需要保存额外的信息,比如节点数量、树的高度等,也是需要考虑的。 然后,用户可能关心的是具体的实现步骤,比如如何遍历树并写入文件,如何读取文件并重建树。例如,递归方法在写入时比较直观,但可能存在栈溢出的风险;而非递归方法(如使用栈或队列)则更安全,但代码可能更复杂。 还有,同步过程中是否需要处理异常情况,比如文件写入失败、数据损坏等。这时候可能需要考虑事务性的处理,比如先写入临时文件,再替换原文件,以确保数据的完整性。 另外,用户可能的应用场景是什么?如果是需要频繁同步的小型树,可能更注重实现的简单性;如果是大型树,可能更关注效率和存储空间。同时,是否需要跨平台兼容性,比如不同的操作系统对文件换行的处理不同,可能会影响文本文件的解析。 最后,是否需要考虑版本兼容性,即未来数据结构变时,旧文件如何升级。这可能需要在文件中包含版本信息,或者在序列时保留扩展性。 总结下来,用户可能需要一个具体的步骤说明,包括如何选择序列方法、遍历方式、文件格式的选择,以及具体的代码示例。同时,需要比较不同方法的优缺点,帮助用户根据实际需求选择最合适的方案。</think>将链式存储的二叉树同步到文件的核心是通过 **序列(Serialization)** 将非线性树结构转换为线性存储格式,并确保可逆反序列(Deserialization)。以下是分步说明和关键技术实现: --- ### 一、基本原理 链式二叉树的节点结构(以C++为例): ```cpp struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} }; ``` **同步目标**:将节点数据和父子关系完整保存到文件,并能准确重建原始树结构。 --- ### 二、序列策略 #### 1. **递归先序遍历 + 空节点标记法**(最常用) - **文件格式**:文本文件(如`.txt`) - **规则**: - 用特殊符号(如`#`)标记空节点 - 节点值之间用分隔符(如逗号`,`或空格)隔开 **示例序列结果**: ``` 1,2,#,#,3,4,#,#,5,#,# ``` 对应的树结构: ``` 1 / \ 2 3 / \ 4 5 ``` #### 2. 层次遍历法(BFS) - **优势**:避免递归栈溢出,适合深树 - **实现**:用队列记录节点,空子节点显式标记 **示例序列结果**: ``` 1,2,3,#,#,4,5,#,#,#,# ``` --- ### 三、代码实现(Python示例) #### 序列过程 ```python def serialize(root): def preorder(node): if not node: return ["#"] return [str(node.val)] + preorder(node.left) + preorder(node.right) return ",".join(preorder(root)) ``` **文件写入**: ```python with open("tree.txt", "w") as f: f.write(serialize(root)) ``` #### 反序列过程 ```python def deserialize(data): nodes = iter(data.split(",")) def build(): val = next(nodes) if val == "#": return None node = TreeNode(int(val)) node.left = build() node.right = build() return node return build() ``` **文件读取**: ```python with open("tree.txt", "r") as f: root = deserialize(f.read()) ``` --- ### 四、关键问与优 #### 1. **分隔符选择** - 推荐使用不可见字符(如`\0`)或JSON格式避免值冲突 - 二进制优示例(C++): ```cpp // 节点存储结构 #pragma pack(push, 1) struct FileNode { int val; bool has_left; bool has_right; }; #pragma pack(pop) ``` #### 2. **大数据优** - **增量同步**:仅保存修改的子树 - **压缩算法**:对重复空节点进行行程编码(RLE) ``` // 原始:1,#,#,3,#,# // 压缩:1,[#]x2,3,[#]x2 ``` #### 3. **版本兼容性** 在文件头部添加元数据: ```json { "version": "1.1", "encoding": "UTF-8", "created_at": "2023-10-05T14:30:00Z" } ``` --- ### 五、不同语言对比 | 语言 | 序列库 | 特点 | |--------|-----------------------|--------------------------| | Java | `ObjectOutputStream` | 需实现`Serializable`接口 | | Python | `pickle` | 支持复杂对象但不安全 | | C++ | Boost.Serialization | 需手动注册类 | --- ### 六、应用场景建议 1. **配置文件存储**:使用JSON/XML格式(可读性强) 2. **高频更新场景**:二进制格式 + 内存映射文件 3. **跨平台传输**:Protobuf/FlatBuffers(高效跨语言) --- 通过选择适当的序列策略和优手段,可以实现链式二叉树的高效文件同步,同时兼顾存储效率与重建准确性。实际开发中需根据数据规模、更新频率和系统环境综合权衡设计。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值