目录
问题描述
序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。
请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。
示例
示例 1:
输入:
root = [1,2,3,null,null,4,5]
输出:
[1,2,3,null,null,4,5]
示例 2:
输入:
root = []
输出:
[]
示例 3:
输入:
root = [1]
输出:
[1]
示例 4:
输入:
root = [1,2]
输出:
[1,2]
提示
- 树中结点数在范围 [0, 104] 内
- -1000 <= Node.val <= 1000
原题链接::https://leetcode.cn/problems/xu-lie-hua-er-cha-shu-lcof/description/ 及 https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree/ 。
思路解析
本题要求设计一个算法来实现二叉树的序列化与反序列化。序列化将二叉树转换为字符串,反序列化则将字符串重构为原始的二叉树结构。
核心思路:
-
选择遍历方式:
- 前序遍历(先根遍历):一种常用的方法,通过递归访问节点,先访问根节点,然后左子树,最后右子树。
-
处理空节点:
- 在序列化过程中,用特殊符号(如
#
或null
)表示空节点,以确保反序列化时能够正确还原树结构。
- 在序列化过程中,用特殊符号(如
-
序列化过程:
- 使用前序遍历,将节点值按顺序添加到字符串中,节点之间用逗号分隔。
- 遇到空节点时,添加特殊符号。
-
反序列化过程:
- 将序列化的字符串按逗号分割,转换为一个列表。
- 通过递归构建二叉树,按照前序遍历的顺序恢复树结构。
具体步骤:
-
序列化:
- 定义一个递归函数
serialize_helper(node, data)
:- 如果当前节点为空,添加
null
到data
列表。 - 否则,添加节点的值,然后递归序列化左子树和右子树。
- 如果当前节点为空,添加
- 在主函数
serialize(root)
中,初始化一个空列表data
,调用辅助函数,并将data
列表用逗号连接成字符串返回。
- 定义一个递归函数
-
反序列化:
- 定义一个递归函数
deserialize_helper(data_list)
:- 取出
data_list
的第一个元素。 - 如果该元素是
null
,返回None
。 - 否则,创建一个新节点,递归构建其左子树和右子树。
- 取出
- 在主函数
deserialize(data)
中,将字符串按逗号分割成列表data_list
,调用辅助函数返回根节点。
- 定义一个递归函数
复杂度分析:
-
时间复杂度:
- 序列化和反序列化都需要遍历每个节点一次,因此时间复杂度为 O(n),其中 n 是二叉树的节点数。
-
空间复杂度:
- 序列化过程中需要存储所有节点的值,空间复杂度为 O(n)。
- 反序列化过程中递归调用栈的深度与树的高度相关,最坏情况下为 O(n)。
代码实现
Python 实现
# Definition for a binary tree node.
from typing import Optional
class TreeNode:
def __init__(self, val=0, left: Optional['TreeNode']=None, right: Optional['TreeNode']=None):
self.val = val
self.left = left
self.right = right
class Codec:
def serialize(self, root: Optional[TreeNode]) -> str:
"""Encodes a tree to a single string."""
data = []
def serialize_helper(node):
if node is None:
data.append('null')
return
data.append(str(node.val))
serialize_helper(node.left)
serialize_helper(node.right)
serialize_helper(root)
return ','.join(data)
def deserialize(self, data: str) -> Optional[TreeNode]:
"""Decodes your encoded data to tree."""
data_list = data.split(',')
self.index = 0
def deserialize_helper():
if self.index >= len(data_list):
return None
val = data_list[self.index]
self.index += 1
if val == 'null':
return None
node = TreeNode(int(val))
node.left = deserialize_helper()
node.right = deserialize_helper()
return node
return deserialize_helper()
测试代码
import unittest
class Codec:
def serialize(self, root: Optional[TreeNode]) -> str:
"""Encodes a tree to a single string."""
data = []
def serialize_helper(node):
if node is None:
data.append('null')
return
data.append(str(node.val))
serialize_helper(node.left)
serialize_helper(node.right)
serialize_helper(root)
return ','.join(data)
def deserialize(self, data: str) -> Optional[TreeNode]:
"""Decodes your encoded data to tree."""
data_list = data.split(',')
self.index = 0
def deserialize_helper():
if self.index >= len(data_list):
return None
val = data_list[self.index]
self.index += 1
if val == 'null':
return None
node = TreeNode(int(val))
node.left = deserialize_helper()
node.right = deserialize_helper()
return node
return deserialize_helper()
class TestCodec(unittest.TestCase):
def build_tree_from_list(self, lst):
"""Helper function to build tree from level-order list."""
if not lst:
return None
root = TreeNode(lst[0])
queue = deque([root])
i = 1
while queue and i < len(lst):
current = queue.popleft()
if current:
# Assign left child
if i < len(lst) and lst[i] is not None:
current.left = TreeNode(lst[i])
queue.append(current.left)
i += 1
# Assign right child
if i < len(lst) and lst[i] is not None:
current.right = TreeNode(lst[i])
queue.append(current.right)
i += 1
return root
def trees_are_equal(self, t1: Optional[TreeNode], t2: Optional[TreeNode]) -> bool:
"""Helper function to compare two trees."""
if not t1 and not t2:
return True
if not t1 or not t2:
return False
return (t1.val == t2.val and
self.trees_are_equal(t1.left, t2.left) and
self.trees_are_equal(t1.right, t2.right))
def test_example1(self):
codec = Codec()
tree = [1,2,3,None,None,4,5]
root = self.build_tree_from_list(tree)
serialized = codec.serialize(root)
expected = "1,2,null,null,3,4,null,null,5,null,null"
self.assertEqual(serialized, expected, "示例1序列化失败")
deserialized = codec.deserialize(serialized)
self.assertTrue(self.trees_are_equal(root, deserialized), "示例1反序列化失败")
def test_example2(self):
codec = Codec()
tree = []
root = self.build_tree_from_list(tree)
serialized = codec.serialize(root)
expected = "null"
self.assertEqual(serialized, expected, "示例2序列化失败")
deserialized = codec.deserialize(serialized)
self.assertTrue(self.trees_are_equal(root, deserialized), "示例2反序列化失败")
def test_example3(self):
codec = Codec()
tree = [1]
root = self.build_tree_from_list(tree)
serialized = codec.serialize(root)
expected = "1,null,null"
self.assertEqual(serialized, expected, "示例3序列化失败")
deserialized = codec.deserialize(serialized)
self.assertTrue(self.trees_are_equal(root, deserialized), "示例3反序列化失败")
def test_example4(self):
codec = Codec()
tree = [1,2]
root = self.build_tree_from_list(tree)
serialized = codec.serialize(root)
expected = "1,2,null,null,null"
self.assertEqual(serialized, expected, "示例4序列化失败")
deserialized = codec.deserialize(serialized)
self.assertTrue(self.trees_are_equal(root, deserialized), "示例4反序列化失败")
def test_single_node(self):
codec = Codec()
tree = [10]
root = self.build_tree_from_list(tree)
serialized = codec.serialize(root)
expected = "10,null,null"
self.assertEqual(serialized, expected, "单节点序列化失败")
deserialized = codec.deserialize(serialized)
self.assertTrue(self.trees_are_equal(root, deserialized), "单节点反序列化失败")
def test_left_skewed(self):
codec = Codec()
tree = [1,2,None,3,None,4,None]
root = self.build_tree_from_list(tree)
serialized = codec.serialize(root)
expected = "1,2,3,4,null,null,null,null,null"
self.assertEqual(serialized, expected, "左倾序列化失败")
deserialized = codec.deserialize(serialized)
self.assertTrue(self.trees_are_equal(root, deserialized), "左倾反序列化失败")
def test_right_skewed(self):
codec = Codec()
tree = [1,None,2,None,3,None,4]
root = self.build_tree_from_list(tree)
serialized = codec.serialize(root)
expected = "1,null,2,null,3,null,4,null,null"
self.assertEqual(serialized, expected, "右倾序列化失败")
deserialized = codec.deserialize(serialized)
self.assertTrue(self.trees_are_equal(root, deserialized), "右倾反序列化失败")
def test_complex_tree(self):
codec = Codec()
tree = [5,3,8,1,4,7,9,None,2]
root = self.build_tree_from_list(tree)
serialized = codec.serialize(root)
expected = "5,3,1,null,2,null,null,4,null,null,8,7,null,null,9,null,null"
self.assertEqual(serialized, expected, "复杂树序列化失败")
deserialized = codec.deserialize(serialized)
self.assertTrue(self.trees_are_equal(root, deserialized), "复杂树反序列化失败")
def test_null_tree(self):
codec = Codec()
tree = []
root = self.build_tree_from_list(tree)
serialized = codec.serialize(root)
expected = "null"
self.assertEqual(serialized, expected, "空树序列化失败")
deserialized = codec.deserialize(serialized)
self.assertTrue(self.trees_are_equal(root, deserialized), "空树反序列化失败")
if __name__ == "__main__":
from collections import deque
unittest.main(argv=[''], exit=False)
输出:
.........
----------------------------------------------------------------------
Ran 8 tests in 0.XXXs
OK
复杂度分析
时间复杂度
-
序列化:
- 需要遍历每个节点一次,时间复杂度为 O(n),其中 n 是二叉树的节点数。
-
反序列化:
- 需要遍历序列化后的字符串中的每个元素一次,时间复杂度为 O(n),其中 n 是二叉树的节点数。
空间复杂度
-
序列化:
- 需要存储序列化结果,空间复杂度为 O(n)。
-
反序列化:
- 需要存储所有节点值的列表,空间复杂度为 O(n)。
- 递归调用栈的空间复杂度与树的高度相关,最坏情况下为 O(n)。
通过上述方法,我们可以高效地实现二叉树的序列化与反序列化。采用前序遍历的方法简单直观,确保了序列化后的字符串能够完整地表示二叉树的结构。在实际应用中,这种方法适用于需要存储或传输二叉树结构的场景。
标签:null,data,self,tree,二叉树,序列化,root,刷题 From: https://blog.csdn.net/weixin_44329069/article/details/144959109