题目描述
请实现两个函数,分别用来序列化和反序列化二叉树。
你需要设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。
提示:输入输出格式与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。
示例:
1
/ \
2 3
/ \
4 5
输入:root = [1,2,3,null,null,4,5]
输出:[1,2,3,null,null,4,5]
Leetcode链接:剑指offer面试题37:序列化二叉树
算法分析
- 序列化:通过深度优先搜索实现序列化,遇到子节点为空则用空格符表示。在BFS的过程中,对每一个节点的子节点进行判断,若子节点不为空,则将其加入nodes数组中;否则将一个值为nil的节点加入nodes数组中(相当于为叶子节点加上终止符)。因此若当前节点的值为空,说明不用考虑当前节点的子节点。
- 反序列化:根据二叉树的数组表示中节点与数组索引的关系(即tree[i]的左子节点为tree[2i],右子节点为tree[2i+1])可以推断出二叉树中每一个节点在字符串中的位置。
复杂度分析
- 序列化:问题规模为树的节点数n
时间复杂度:O( n n n), 广度优先遍历树的每一个节点
空间复杂度:O( n n n), 需要一个额外的nodes数组 - 反序列化: 问题规模为字符串长度n
时间复杂度:O( n n n),需要构建树的每一个节点,节点数m等于字符串长度n
空间复杂度:O( 1 1 1)
没有完全遵从leetcode的序列化格式
最终输出结果:
123 45
[1 2 3 4 5]
Golang代码如下
func serialize(root *tree.BinaryTreeNode) string {
if root == nil {
return ""
}
bfs := func(node *tree.BinaryTreeNode) string {
str := ""
if node != nil {
nodes := []*tree.BinaryTreeNode{node}
for len(nodes) > 0 {
curNode := nodes[0]
nodes = nodes[1:]
if curNode.GetValue() != nil {
str += curNode.GetValue().(string)
} else {
str += " "
}
if curNode.GetValue() != nil {
if curNode.Left != nil {
nodes = append(nodes, curNode.Left)
} else {
nodes = append(nodes, tree.NewBinaryTreeNode(nil))
}
}
if curNode.GetValue() != nil {
if curNode.Right != nil {
nodes = append(nodes, curNode.Right)
} else {
nodes = append(nodes, tree.NewBinaryTreeNode(nil))
}
}
}
}
return str
}
res := bfs(root)
return string(res)
}
func insert(node *tree.BinaryTreeNode, i int, data string) {
if 2*i + 1 < len(data) {
if data[2*i - 1] != ' ' {
node.Left = tree.NewBinaryTreeNode(string(data[2*i - 1]))
}
if data[2*i] != ' ' {
node.Right = tree.NewBinaryTreeNode(string(data[2*i]))
}
if data[2*i - 1] != ' ' {
insert(node.Left, 2*i, data)
}
if data[2*i] != ' ' {
insert(node.Right, 2*i+1, data)
}
}
}
func deserialize(data string) (root *tree.BinaryTreeNode) {
root = tree.NewBinaryTreeNode(string(data[0]))
insert(root, 1, data)
return
}