news 2026/4/30 23:34:49

LeetCode 449 - 序列化和反序列化二叉搜索树

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LeetCode 449 - 序列化和反序列化二叉搜索树


文章目录

    • 摘要
    • 描述
    • 题解答案(核心思路)
      • 为什么普通二叉树和 BST 不一样?
      • BST 的关键点
      • 本题采用的策略
    • 题解代码(Swift 可运行 Demo)
    • 题解代码分析
      • 1. 为什么用前序遍历?
      • 2. serialize 的核心逻辑
      • 3. deserialize 的核心逻辑
      • 4. 为什么不需要回退 index?
    • 示例测试及结果
    • 时间复杂度
    • 空间复杂度
    • 总结

摘要

「序列化和反序列化二叉搜索树」这道题,表面上是在考二叉树,其实真正的考点在于:你有没有真正理解 BST(Binary Search Tree)的性质

如果把它当成普通二叉树去做,确实可以用层序遍历,加上null占位来解决,但那样字符串会很长,也完全没有利用 BST 的特性。而题目特意强调了一句:

编码的字符串应尽可能紧凑。

这其实是在暗示:
BST 是可以只靠遍历顺序恢复出来的。

这篇文章会从实际业务场景聊起,解释为什么 BST 可以被“无损压缩”,再一步步带你用 Swift 写出一套简洁、高效、可运行的解法。

描述

题目要求我们设计一套算法,用来:

  • 把一棵二叉搜索树序列化成字符串
  • 再从这个字符串中反序列化,恢复成原来的 BST

有几个关键限制条件:

  1. 输入保证一定是一棵 BST
  2. 节点值范围是合法整数
  3. 节点数量最多 10⁴
  4. 序列化字符串要尽量紧凑

BST 有一个非常重要的性质:

  • 左子树所有节点值 < 根节点
  • 右子树所有节点值 > 根节点

这条规则,是我们能“少存信息、还能完整还原”的关键。

题解答案(核心思路)

为什么普通二叉树和 BST 不一样?

如果是普通二叉树,你只存前序遍历是没法还原结构的,比如:

1 \ 2

1 / 2

前序遍历都是[1,2],结构信息丢失了。

但 BST 不一样。

BST 的关键点

只要你知道:

  • 遍历顺序(比如前序)
  • BST 的大小关系规则

那么不用存 null,也能恢复结构

本题采用的策略

  1. 序列化

    • 使用前序遍历(root → left → right)
    • 只记录节点值
    • 用逗号拼成字符串
  2. 反序列化

    • 根据 BST 的区间规则递归构建
    • 每个节点值都必须落在合法区间(min, max)
    • 一次遍历即可还原整棵树

这样做的好处是:

  • 字符串非常紧凑
  • 时间和空间效率都很高
  • 思路清晰,代码不复杂

题解代码(Swift 可运行 Demo)

下面是完整可运行的 Swift 示例,包括TreeNode定义和测试代码。

importFoundationpublicclassTreeNode{publicvarval:Intpublicvarleft:TreeNode?publicvarright:TreeNode?publicinit(_val:Int){self.val=valself.left=nilself.right=nil}}classCodec{// MARK: - Serializefuncserialize(_root:TreeNode?)->String{varresult:[String]=[]funcpreorder(_node:TreeNode?){guardletnode=nodeelse{return}result.append(String(node.val))preorder(node.left)preorder(node.right)}preorder(root)returnresult.joined(separator:",")}// MARK: - Deserializefuncdeserialize(_data:String)->TreeNode?{ifdata.isEmpty{returnnil}varvalues=data.split(separator:",").map{Int($0)!}varindex=0funcbuild(_min:Int,_max:Int)->TreeNode?{ifindex>=values.count{returnnil}letval=values[index]ifval<min||val>max{returnnil}index+=1letnode=TreeNode(val)node.left=build(min,val)node.right=build(val,max)returnnode}returnbuild(Int.min,Int.max)}}

题解代码分析

1. 为什么用前序遍历?

前序遍历的第一个节点一定是根节点,这对构建树非常友好。

BST 的前序遍历有一个隐含规律:

  • 一段连续小于 root 的值,一定属于左子树
  • 后面大于 root 的值,一定属于右子树

结合区间限制,我们就能精准判断一个值“该不该被消费”。

2. serialize 的核心逻辑

funcpreorder(_node:TreeNode?){guardletnode=nodeelse{return}result.append(String(node.val))preorder(node.left)preorder(node.right)}

这里非常直接:

  • 不存 null
  • 不加多余符号
  • 单纯记录节点值

这也是字符串“足够紧凑”的关键原因。

3. deserialize 的核心逻辑

funcbuild(_min:Int,_max:Int)->TreeNode?

这是整个算法的精髓。

含义是:

  • 当前子树中,合法节点值必须在(min, max)区间内
  • 如果当前值不在区间内,说明它属于别的子树,直接返回 nil
  • 如果合法,就创建节点,并递归构建左右子树

因为index是全局递增的,所以每个节点只会被处理一次。

4. 为什么不需要回退 index?

这是很多人一开始想不通的点。

原因在于:

  • 前序遍历是严格的「根 → 左 → 右」
  • 一旦某个值不在当前区间,它一定属于后续的右子树或祖先节点
  • 所以不能消费,就不动 index

这是 BST 性质带来的好处。

示例测试及结果

我们用示例一来跑一遍:

letcodec=Codec()letroot=TreeNode(2)root.left=TreeNode(1)root.right=TreeNode(3)letdata=codec.serialize(root)print("序列化结果:",data)letnewRoot=codec.deserialize(data)print("反序列化完成,根节点:",newRoot?.val??-1)

输出结果:

序列化结果: 2,1,3 反序列化完成,根节点: 2

对于空树:

print(codec.serialize(nil))// ""print(codec.deserialize("")==nil)// true

结果也是符合预期的。

时间复杂度

  • 序列化:每个节点访问一次,O(n)
  • 反序列化:每个节点构建一次,O(n)

总体时间复杂度:O(n)

空间复杂度

  • 序列化字符串占 O(n)
  • 递归调用栈最坏 O(n)(退化成链表)

总体空间复杂度:O(n)

总结

LeetCode 449 是一道非常经典的「理解型」题目。

它并不难写,但非常考察你是否真正理解了:

  • BST 的结构特性
  • 遍历顺序和树结构之间的关系
  • 如何用“约束条件”减少冗余数据
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 7:56:12

前端农业商城中产品产地溯源功能的实现

一、需求分析&#xff1a;溯源功能的核心价值在项目开始前&#xff0c;我们明确了溯源功能的三个核心目标&#xff1a;信任建立 - 通过透明化供应链增强消费者信心体验提升 - 提供直观、有趣的农产品旅程可视化营销增值 - 将溯源过程转化为产品卖点二、技术架构设计前端技术栈选…

作者头像 李华
网站建设 2026/5/1 8:01:44

AI之LLMs:当 AI 成为常驻合作者—AI 让我们做更多,也让我们担心更多:Anthropic 的使用数据与体验洞察—Claude 在岗位上的影响(产能、技能与协作的双刃剑)

AI之LLMs&#xff1a;当 AI 成为常驻合作者—AI 让我们做更多&#xff0c;也让我们担心更多&#xff1a;Anthropic 的使用数据与体验洞察—Claude 在岗位上的影响(产能、技能与协作的双刃剑) 导读&#xff1a;Anthropic的这项内部研究提供了一个独特而深入的视角&#xff0c;揭…

作者头像 李华
网站建设 2026/5/1 6:14:05

从对话演示到智能工作平台:ChatGPT的三年演进史(2022-2025)

1 从“对话演示”到“通用入口”&#xff1a;ChatGPT 的起点与早期定位&#xff08;2022 年 11–12 月&#xff09; 1.1 2022 年底的 ChatGPT&#xff1a;并不是“一个模型”&#xff0c;而是一种交互范式 回到 2022 年 11 月 30 日&#xff0c;OpenAI 把“ChatGPT”推向公众…

作者头像 李华