1
1
from __future__ import annotations
2
2
3
+ from collections .abc import Iterator
4
+ from dataclasses import dataclass
3
5
6
+
7
+ @dataclass
4
8
class TreeNode :
5
9
"""
6
10
A binary tree node has a value, left child, and right child.
7
11
8
12
Props:
9
- val(int) : The value of the node.
13
+ value : The value of the node.
10
14
left: The left child of the node.
11
15
right: The right child of the node.
12
16
"""
13
17
14
- def __init__ (
15
- self ,
16
- val : int = 0 ,
17
- left : TreeNode | None = None ,
18
- right : TreeNode | None = None ,
19
- ) -> None :
20
- if not isinstance (val , int ):
21
- raise TypeError ("Value must be an integer." )
22
- self .val = val
23
- self .left = left
24
- self .right = right
25
-
26
-
27
- # Helper functions
28
- def are_trees_identical (root1 : TreeNode | None , root2 : TreeNode | None ) -> bool :
29
- """
30
- Check if two binary trees are identical.
31
-
32
- Args:
33
- root1 (TreeNode): Tree 1
34
- root2 (TreeNode): Tree 2
35
-
36
- Returns:
37
- bool: True if the trees are identical, False otherwise.
38
-
39
- >>> root1 = TreeNode(1)
40
- >>> root1.left = TreeNode(2)
41
- >>> root1.right = TreeNode(3)
42
- >>> root2 = TreeNode(1)
43
- >>> root2.left = TreeNode(2)
44
- >>> root2.right = TreeNode(3)
45
- >>> are_trees_identical(root1, root2)
46
- True
47
- >>> root1 = TreeNode(1)
48
- >>> root1.left = TreeNode(2)
49
- >>> root1.right = TreeNode(3)
50
- >>> root2 = TreeNode(1)
51
- >>> root2.left = TreeNode(2)
52
- >>> root2.right = TreeNode(4)
53
- >>> are_trees_identical(root1, root2)
54
- False
55
- """
56
-
57
- if not root1 and not root2 :
58
- return True
59
- if not root1 or not root2 :
60
- return False
61
-
62
- return (
63
- root1 .val == root2 .val
64
- and are_trees_identical (root1 .left , root2 .left )
65
- and are_trees_identical (root1 .right , root2 .right )
66
- )
18
+ value : int = 0
19
+ left : TreeNode | None = None
20
+ right : TreeNode | None = None
67
21
22
+ def __post_init__ (self ):
23
+ if not isinstance (self .value , int ):
24
+ raise TypeError ("Value must be an integer." )
68
25
69
- # Main functions
70
- def serialize (root : TreeNode | None ) -> str :
71
- """
72
- Serialize a binary tree to a string using preorder traversal.
73
-
74
- Args:
75
- root(TreeNode): The root of the binary tree.
76
-
77
- Returns:
78
- A string representation of the binary tree.
79
-
80
- >>> root = TreeNode(1)
81
- >>> root.left = TreeNode(2)
82
- >>> root.right = TreeNode(3)
83
- >>> root.right.left = TreeNode(4)
84
- >>> root.right.right = TreeNode(5)
85
- >>> serialize(root)
86
- '1,2,null,null,3,4,null,null,5,null,null'
87
- >>> root = TreeNode(1)
88
- >>> serialize(root)
89
- '1,null,null'
90
- """
91
-
92
- # Use "null" to represent empty nodes in the serialization
93
- if not root :
94
- return "null"
95
-
96
- return str (root .val ) + "," + serialize (root .left ) + "," + serialize (root .right )
26
+ def __iter__ (self ) -> Iterator [TreeNode ]:
27
+ """
28
+ Iterate through the tree in preorder.
29
+
30
+ Returns:
31
+ An iterator of the tree nodes.
32
+
33
+ >>> list(TreeNode(1))
34
+ [1,null,null]
35
+ >>> tuple(TreeNode(1, TreeNode(2), TreeNode(3)))
36
+ (1,2,null,null,3,null,null, 2,null,null, 3,null,null)
37
+ """
38
+ yield self
39
+ yield from self .left or ()
40
+ yield from self .right or ()
41
+
42
+ def __len__ (self ) -> int :
43
+ """
44
+ Count the number of nodes in the tree.
45
+
46
+ Returns:
47
+ The number of nodes in the tree.
48
+
49
+ >>> len(TreeNode(1))
50
+ 1
51
+ >>> len(TreeNode(1, TreeNode(2), TreeNode(3)))
52
+ 3
53
+ """
54
+ return sum (1 for _ in self )
55
+
56
+ def __repr__ (self ) -> str :
57
+ """
58
+ Represent the tree as a string.
59
+
60
+ Returns:
61
+ A string representation of the tree.
62
+
63
+ >>> repr(TreeNode(1))
64
+ '1,null,null'
65
+ >>> repr(TreeNode(1, TreeNode(2), TreeNode(3)))
66
+ '1,2,null,null,3,null,null'
67
+ >>> repr(TreeNode(1, TreeNode(2), TreeNode(3, TreeNode(4), TreeNode(5))))
68
+ '1,2,null,null,3,4,null,null,5,null,null'
69
+ """
70
+ return f"{ self .value } ,{ self .left !r} ,{ self .right !r} " .replace ("None" , "null" )
71
+
72
+ @classmethod
73
+ def five_tree (cls ) -> TreeNode :
74
+ """
75
+ >>> repr(TreeNode.five_tree())
76
+ '1,2,null,null,3,4,null,null,5,null,null'
77
+ """
78
+ root = TreeNode (1 )
79
+ root .left = TreeNode (2 )
80
+ root .right = TreeNode (3 )
81
+ root .right .left = TreeNode (4 )
82
+ root .right .right = TreeNode (5 )
83
+ return root
97
84
98
85
99
86
def deserialize (data : str ) -> TreeNode | None :
@@ -106,44 +93,42 @@ def deserialize(data: str) -> TreeNode | None:
106
93
Returns:
107
94
The root of the binary tree.
108
95
109
- >>> root = TreeNode(1)
110
- >>> root.left = TreeNode(2)
111
- >>> root.right = TreeNode(3)
112
- >>> root.right.left = TreeNode(4)
113
- >>> root.right.right = TreeNode(5)
114
- >>> serialzed_data = serialize(root)
96
+ >>> root = TreeNode.five_tree()
97
+ >>> serialzed_data = repr(root)
115
98
>>> deserialized = deserialize(serialzed_data)
116
- >>> are_trees_identical( root, deserialized)
99
+ >>> root == deserialized
117
100
True
118
- >>> root = TreeNode(1)
119
- >>> serialzed_data = serialize(root)
120
- >>> dummy_data = "1,2,null,null,3,4,null,null,5,null,null"
121
- >>> deserialized = deserialize(dummy_data)
122
- >>> are_trees_identical(root, deserialized)
101
+ >>> root is deserialized # two separate trees
102
+ False
103
+ >>> root.right.right.value = 6
104
+ >>> root == deserialized
123
105
False
106
+ >>> serialzed_data = repr(root)
107
+ >>> deserialized = deserialize(serialzed_data)
108
+ >>> root == deserialized
109
+ True
124
110
>>> deserialize("")
125
111
Traceback (most recent call last):
126
112
...
127
113
ValueError: Data cannot be empty.
128
114
"""
129
115
130
- if data == "" :
116
+ if not data :
131
117
raise ValueError ("Data cannot be empty." )
132
118
133
- # Split the serialized string by comma to get node values
119
+ # Split the serialized string by a comma to get node values
134
120
nodes = data .split ("," )
135
121
136
122
def build_tree () -> TreeNode | None :
137
123
# Get the next value from the list
138
- val = nodes .pop (0 )
124
+ value = nodes .pop (0 )
139
125
140
- if val == "null" :
126
+ if value == "null" :
141
127
return None
142
128
143
- node = TreeNode (int (val ))
129
+ node = TreeNode (int (value ))
144
130
node .left = build_tree () # Recursively build left subtree
145
131
node .right = build_tree () # Recursively build right subtree
146
-
147
132
return node
148
133
149
134
return build_tree ()
0 commit comments