分析
中、前序遍历还原法
初看时的做法可能是利用“中序遍历+前序遍历还原二叉树”的做法,在序列化时同时输出中序、前序遍历的字符串,以"|“相隔即可。反序列化时先以”|"取中、前序遍历字符串,再还原即可。
但这种做法的序列化消耗稍微较大,如果有n个节点,输出空间约有 2 n 2n 2n。
遍历还原法
留意到二叉搜索树的特性是,左子树的节点都小于根节点,右子树节点都大于。所以:
- 序列化时,只需要按前序遍历序列化即可。
- 反序列化时,字符串首节点是根节点,从左向右遍历,小于根节点的都在左子树,而大于的都在右子树。
空节点标识法
遇到空节点时标识为"#"。具体做法略。
后序遍历+范围递归法
官方题解的递归思路很巧妙。它不像大家常规的做法,先搜索数组寻找数组中左右子树的分界点,而是定义值范围。
递归的含义可以理解为:给定一个节点数组,其队尾的若干元素是一棵子树,按后序遍历排列。你的递归函数规定了这个子树的值范围,如何将子树结构还原出来。
class Codec:
def serialize(self, root: TreeNode) -> str:
arr = []
def postOrder(root: TreeNode) -> None:
if root is None:
return
postOrder(root.left)
postOrder(root.right)
arr.append(root.val)
postOrder(root)
return ' '.join(map(str, arr))
def deserialize(self, data: str) -> TreeNode:
arr = list(map(int, data.split()))
def construct(lower: int, upper: int) -> TreeNode:
if arr == [] or arr[-1] < lower or arr[-1] > upper:
return None
val = arr.pop()
root = TreeNode(val)
root.right = construct(val, upper)
root.left = construct(lower, val)
return root
return construct(-inf, inf)
本人答案与官方题解思路大体一致:
注意,deserialize对解码进行了特例判断:
if data == "":
return []
这是因为对于空字符串""
,split(",")
会返回节点列表。python split函数对split()和split(“,”)两种情况的行为是不同的。
class Codec:
def serialize(self, root: TreeNode) -> str:
"""Encodes a tree to a single string.
"""
res = []
def dfs(root):
if root is None:
return
dfs(root.left)
dfs(root.right)
res.append(root.val)
dfs(root)
res = list(map(str, res))
return ",".join(res)
def deserialize(self, data: str) -> TreeNode:
"""Decodes your encoded data to tree.
"""
if data == "":
return []
nodes = data.split(",")
nodes = list(map(int, nodes))
def decode(low, high):
if len(nodes) == 0 or nodes[-1] < low or nodes[-1] > high:
return None
root = TreeNode(nodes[-1])
nodes.pop(-1)
root.right = decode(root.val, high)
root.left = decode(low, root.val)
return root
return decode(float("-inf"), float("inf"))