Serialize and Deserialize Binary Tree hard
Problem Statement
Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment.
Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serialization/deserialization algorithm should work. 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.
Clarification: The input/output format is the same as how LeetCode serializes a binary tree. You do not necessarily need to follow this format, so please be creative and efficient.
Example 1:
Input: root = [1,2,3,null,null,4,5]
Output: [1,2,3,null,null,4,5]
Example 2:
Input: root = []
Output: []
Steps:
-
Serialization: We'll use a preorder traversal (root, left, right) with a special marker to indicate null nodes. This ensures we can reconstruct the tree uniquely. Null nodes are represented as "N".
-
Deserialization: We'll use a queue to reconstruct the tree from the serialized string. We pop from the queue to get the next node value. If it's not "N", we create a new node and add its left and right children (obtained by further popping from the queue) as appropriate.
Explanation:
Serialization: The preorder traversal guarantees that we process the root node first, followed by its left subtree, and then its right subtree. By using "N" to represent null nodes, we preserve the tree structure even when nodes are missing.
Deserialization: The queue ensures that nodes are processed in the correct order as dictated by the preorder traversal. We read the next value from the queue, and if it's not "N", we create a node and recursively process its children (reading from the queue for their values).
Code:
class TreeNode(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Codec:
def serialize(self, root):
"""Encodes a tree to a single string.
:type root: TreeNode
:rtype: str
"""
if not root:
return "N,"
return str(root.val) + "," + self.serialize(root.left) + self.serialize(root.right)
def deserialize(self, data):
"""Decodes your encoded data to tree.
:type data: str
:rtype: TreeNode
"""
vals = data.split(",")
self.i = 0
return self.buildTree(vals)
def buildTree(self,vals):
if self.i >= len(vals) or vals[self.i] == "N":
self.i+=1
return None
root = TreeNode(int(vals[self.i]))
self.i+=1
root.left = self.buildTree(vals)
root.right = self.buildTree(vals)
return root
# Your Codec object will be instantiated and called as such:
# codec = Codec()
# codec.deserialize(codec.serialize(root))
Complexity:
-
Time Complexity: Both serialization and deserialization have a time complexity of O(N), where N is the number of nodes in the binary tree. This is because we visit each node exactly once during both processes.
-
Space Complexity: The space complexity is O(N) for both serialization and deserialization. Serialization uses space proportional to the number of nodes in the string representation (at worst, 2N characters), while deserialization uses space for the recursion stack (which can be at most N levels deep) and the queue used for the iterative approach (which in the worst case holds all nodes).