Design an algorithm to serialize a binary tree into a string and deserialize that string back into the original tree structure. Serialization converts the tree into a format that can be stored or transmitted, and deserialization reconstructs the tree from that format. There is no restriction on how your serialization and deserialization algorithms should work, as long as a tree can be serialized and then deserialized back to the same structure.
Example 1
Input: root = [1,2,3,4,5,6,7]
Output: [1,2,3,4,5,6,7]
Explanation: Serializing the full 3-level tree to a string and decoding that string rebuilds exactly the same tree, [1,2,3,4,5,6,7].
Example 2
Input: root = [1,2,3,null,null,4,5]
Output: [1,2,3,null,null,4,5]
Explanation: Node 2 has no children and node 3 has children 4 and 5. The missing children are recorded as null so that decoding puts 4 and 5 under 3, not under 2.
Example 3
Input: root = []
Output: []
Explanation: An empty tree serializes to an empty representation and decodes back to an empty tree.
Pre-order traversal (root, left, right) does *not* uniquely determine a binary tree on its own — `[1, 2]` could mean "root 1 with left child 2" or "root 1 with right child 2". Adding explicit null markers fixes this: the sequence becomes a complete recipe the deserializer can follow blindly.
Run checks all cases above. Submit evaluates all test cases.