1+ import unittest
2+ from typing import Optional , List
3+ from delete import TreeNode , Solution
4+
5+ class TestDeleteNodes (unittest .TestCase ):
6+
7+ def tree_to_list (self , root : Optional [TreeNode ]) -> List :
8+ """Helper: Convert tree to level-order list for comparison"""
9+ if not root :
10+ return []
11+ result = []
12+ queue = [root ]
13+ while queue :
14+ node = queue .pop (0 )
15+ if node :
16+ result .append (node .val )
17+ queue .append (node .left )
18+ queue .append (node .right )
19+ else :
20+ result .append (None )
21+ # Remove trailing Nones
22+ while result and result [- 1 ] is None :
23+ result .pop ()
24+ return result
25+
26+ def test_example_1 (self ):
27+ """Test case from example 1: delete nodes 3 and 5"""
28+ # Tree: [1,2,3,4,5,6,7]
29+ root = TreeNode (1 ,
30+ TreeNode (2 , TreeNode (4 ), TreeNode (5 )),
31+ TreeNode (3 , TreeNode (6 ), TreeNode (7 )))
32+
33+ solution = Solution ()
34+ result = solution .delNodes (root , [3 , 5 ])
35+
36+ # Convert results to lists for easier comparison
37+ result_lists = sorted ([self .tree_to_list (tree ) for tree in result ])
38+
39+ # Expected: [[1,2,null,4], [6], [7]]
40+ expected = sorted ([[1 , 2 , None , 4 ], [6 ], [7 ]])
41+
42+ self .assertEqual (result_lists , expected )
43+
44+ def test_example_2 (self ):
45+ """Test case from example 2: delete node 3"""
46+ # Tree: [1,2,4,null,3]
47+ root = TreeNode (1 ,
48+ TreeNode (2 , None , TreeNode (3 )),
49+ TreeNode (4 ))
50+
51+ solution = Solution ()
52+ result = solution .delNodes (root , [3 ])
53+
54+ result_lists = [self .tree_to_list (tree ) for tree in result ]
55+ expected = [[1 , 2 , 4 ]]
56+
57+ self .assertEqual (result_lists , expected )
58+
59+ def test_delete_root_only (self ):
60+ """Delete only the root node"""
61+ root = TreeNode (1 , TreeNode (2 ), TreeNode (3 ))
62+
63+ solution = Solution ()
64+ result = solution .delNodes (root , [1 ])
65+
66+ result_lists = sorted ([self .tree_to_list (tree ) for tree in result ])
67+ expected = sorted ([[2 ], [3 ]])
68+
69+ self .assertEqual (result_lists , expected )
70+
71+ def test_delete_nothing (self ):
72+ """Delete no nodes - return original tree"""
73+ root = TreeNode (1 , TreeNode (2 ), TreeNode (3 ))
74+
75+ solution = Solution ()
76+ result = solution .delNodes (root , [])
77+
78+ self .assertEqual (len (result ), 1 )
79+ self .assertEqual (self .tree_to_list (result [0 ]), [1 , 2 , 3 ])
80+
81+ def test_delete_all_nodes (self ):
82+ """Delete all nodes in tree"""
83+ root = TreeNode (1 , TreeNode (2 ), TreeNode (3 ))
84+
85+ solution = Solution ()
86+ result = solution .delNodes (root , [1 , 2 , 3 ])
87+
88+ self .assertEqual (result , [])
89+
90+ def test_single_node_delete (self ):
91+ """Single node tree, delete it"""
92+ root = TreeNode (1 )
93+
94+ solution = Solution ()
95+ result = solution .delNodes (root , [1 ])
96+
97+ self .assertEqual (result , [])
98+
99+ def test_single_node_keep (self ):
100+ """Single node tree, keep it"""
101+ root = TreeNode (1 )
102+
103+ solution = Solution ()
104+ result = solution .delNodes (root , [])
105+
106+ self .assertEqual (len (result ), 1 )
107+ self .assertEqual (result [0 ].val , 1 )
108+
109+ def test_delete_leaf_nodes (self ):
110+ """Delete only leaf nodes"""
111+ root = TreeNode (1 ,
112+ TreeNode (2 , TreeNode (4 ), TreeNode (5 )),
113+ TreeNode (3 ))
114+
115+ solution = Solution ()
116+ result = solution .delNodes (root , [4 , 5 , 3 ])
117+
118+ self .assertEqual (len (result ), 1 )
119+ self .assertEqual (self .tree_to_list (result [0 ]), [1 , 2 ])
120+
121+ def test_delete_internal_nodes (self ):
122+ """Delete internal nodes creating multiple forests"""
123+ root = TreeNode (1 ,
124+ TreeNode (2 , TreeNode (4 ), TreeNode (5 )),
125+ TreeNode (3 , TreeNode (6 ), TreeNode (7 )))
126+
127+ solution = Solution ()
128+ result = solution .delNodes (root , [2 , 3 ])
129+
130+ result_lists = sorted ([self .tree_to_list (tree ) for tree in result ])
131+ expected = sorted ([[1 ], [4 ], [5 ], [6 ], [7 ]])
132+
133+ self .assertEqual (result_lists , expected )
134+
135+ def test_linear_tree_delete_middle (self ):
136+ """Linear tree (like linked list), delete middle node"""
137+ root = TreeNode (1 , TreeNode (2 , TreeNode (3 , TreeNode (4 ))))
138+
139+ solution = Solution ()
140+ result = solution .delNodes (root , [2 ])
141+
142+ result_lists = sorted ([self .tree_to_list (tree ) for tree in result ])
143+ expected = sorted ([[1 ], [3 , 4 ]])
144+
145+ self .assertEqual (result_lists , expected )
146+
147+ def test_delete_node_with_one_child (self ):
148+ """Delete node that has only one child"""
149+ root = TreeNode (1 ,
150+ TreeNode (2 , TreeNode (4 )),
151+ TreeNode (3 ))
152+
153+ solution = Solution ()
154+ result = solution .delNodes (root , [2 ])
155+
156+ result_lists = sorted ([self .tree_to_list (tree ) for tree in result ])
157+ expected = sorted ([[1 , None , 3 ], [4 ]])
158+
159+ self .assertEqual (result_lists , expected )
160+
161+
162+ if __name__ == '__main__' :
163+ unittest .main (verbosity = 2 )
0 commit comments