Serialize and Deserialize Binary Tree
Implement an algorithm to serialize and deserialize a binary tree.
Serialization is the process of converting an in-memory structure into a sequence of bits so that it can be stored or sent across a network to be reconstructed later in another computer environment.
You just need to ensure that a binary tree can be serialized to a string and this string can be deserialized to the original tree structure. There is no additional restriction on how your serialization/deserialization algorithm should work.
Note: The input/output format in the examples is the same as how NeetCode serializes a binary tree. You do not necessarily need to follow this format.
Example 1:
Input: root = [1,2,3,null,null,4,5]
Output: [1,2,3,null,null,4,5]
Example 2:
Input: root = []
Output: []
Constraints:
0 <= The number of nodes in the tree <= 1000.
-1000 <= Node.val <= 1000
Solution
A classic problem to rebuild a tree from serialized data is building a tree from pre-order traversal and in-order traversal. To do this, we can use recursion function to dive into the subsequence of pre-order and in-order traversal. The first node in pre-order sequence must the root, and the sequence on the left of root in the in-order sequence must be the left child tree of the root, so as the sequence on the right.
However, if we rethink about the process. Why cannot we rebuild the tree only from pre-order traversal? That's because we cannot divide the sequences of the left child tree and right child tree. So, we need to mark where the left child tree ends by adding none nodes. If meet none nodes in DFS, it is time to return. By doing this, we can know where the left child tree ends and start to DFS the right child tree.
Code
Rebuild from pre-order and in-order traversal.
py
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Codec:
# Encodes a tree to a single string.
def serialize(self, root: Optional[TreeNode]) -> str:
if not root:
return ''
preo = []
ino = []
def inorder(node):
if node.left:
inorder(node.left)
ino.append(str(node.val))
if node.right:
inorder(node.right)
def preorder(node):
preo.append(str(node.val))
if node.left:
preorder(node.left)
if node.right:
preorder(node.right)
preorder(root)
prestr = ','.join(preo)
inorder(root)
instr = ','.join(ino)
return prestr+'#'+instr
# Decodes your encoded data to tree.
def deserialize(self, data: str) -> Optional[TreeNode]:
if len(data) == 0:
return None
preorder = data.split('#')[0].split(',')
inorder = data.split('#')[1].split(',')
pre_map = {}
in_map = {}
for i in range(len(preorder)):
pre_map[preorder[i]] = i
in_map[inorder[i]] = i
def dfs(prele, preri, inle, inri):
if prele == preri:
return TreeNode(int(preorder[prele]), None, None)
if prele > preri:
return None
root = preorder[prele]
inrootpos = in_map[root]
ls_size = inrootpos-inle
rs_size = inri-inrootpos
ls = dfs(prele+1, prele+ls_size, inle, inrootpos-1)
rs = dfs(prele+ls_size+1, preri, inrootpos+1, inri)
return TreeNode(int(root), ls, rs)
return dfs(0, len(preorder)-1, 0, len(inorder)-1)
Rebuild by adding none node to pre-order traversal.
py
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Codec:
# Encodes a tree to a single string.
def serialize(self, root: Optional[TreeNode]) -> str:
res = []
def dfs(node):
if not node:
res.append("N")
return
res.append(str(node.val))
dfs(node.left)
dfs(node.right)
dfs(root)
return ",".join(res)
# Decodes your encoded data to tree.
def deserialize(self, data: str) -> Optional[TreeNode]:
vals = data.split(",")
self.i = 0
def dfs():
if vals[self.i] == "N":
self.i += 1
return None
node = TreeNode(int(vals[self.i]))
self.i += 1
node.left = dfs()
node.right = dfs()
return node
return dfs()