Invert Binary Tree#
Solution#
Let’s take a step-by-step walkthrough of your code using an example tree.
Suppose the input tree is:
4
/ \
2 7
/ \ / \
1 3 6 9
First, you call
invertTreeon the root node, which is 4.Since root is not
None, you proceed to callinvertTree(root.left), which callsinvertTreeon node 2.For node 2, you proceed to call
invertTree(root.left), which callsinvertTreeon node 1.For node 1, it’s a leaf node, so
root.leftandroot.rightare bothNone. Thus,invertTree(root.left)andinvertTree(root.right)both returnNone.Since
root.leftandroot.rightfor node 1 are bothNone, swapping them does nothing. The functioninvertTree(1)then returns node 1, which is assigned toleftin theinvertTree(2)call.Back in the
invertTree(2)call, you now callinvertTree(root.right), which callsinvertTreeon node 3. Since node 3 is also a leaf node, the process is the same as for node 1, andinvertTree(3)returns node 3, which is assigned toright.Now, in the
invertTree(2)call, you haveleft = 1andright = 3, you swaproot.leftandroot.right, so node 2’s left child becomes node 3 and its right child becomes node 1. You then return node 2.The process continues similarly for the rest of the tree. For node 4, after the recursive calls to
invertTree(root.left)andinvertTree(root.right),leftbecomes the root of the inverted left subtree andrightbecomes the root of the inverted right subtree. Then you swaproot.leftandroot.rightand return the root.
The inverted tree will be:
4
/ \
7 2
/ \ / \
9 6 3 1
class Solution:
def invertTree(self, root: Optional[BinaryTreeNode]) -> Optional[BinaryTreeNode]:
if root is None:
return None
inverted_left_subtree = self.invertTree(root.left)
inverted_right_subtree = self.invertTree(root.right)
root.left = inverted_right_subtree
root.right = inverted_left_subtree
return root
Here, I’ll keep track of the status and state of the variables root, inverted_left_subtree, and inverted_right_subtree:
Line 2: Call
invertTree(4). Here,root = 4. Variablesinverted_left_subtreeandinverted_right_subtreehaven’t been defined yet.Line 3: We check if
rootisNone, which it isn’t. So we proceed to line 6.Line 6: Call
invertTree(root.left), which isinvertTree(2). This pauses execution forinvertTree(4)and startsinvertTree(2), settingroot = 2.Line 6 of invertTree(2): Call
invertTree(root.left), which isinvertTree(1). This pauses execution forinvertTree(2)and startsinvertTree(1), settingroot = 1.Line 6 of invertTree(1): Call
invertTree(root.left), which isinvertTree(None). This starts a new execution and immediately returnsNone, settinginverted_left_subtree = None.Line 7 of invertTree(1): Call
invertTree(root.right), which isinvertTree(None). This also returnsNone, settinginverted_right_subtree = None.Line 9 and 10 of invertTree(1): Since both
inverted_left_subtreeandinverted_right_subtreeareNone, swappingroot.leftandroot.rightdoes nothing.invertTree(1)returnsroot, which is node 1.Resuming Line 6 of invertTree(2): The
invertTree(1)call returns node 1, which is assigned toinverted_left_subtree.Line 7 of invertTree(2): Call
invertTree(root.right), which isinvertTree(3). This process is similar to the process for node 1, andinvertTree(3)returns node 3, settinginverted_right_subtree = Node(3).Line 9 and 10 of invertTree(2): Swap
root.leftandroot.right, so node 2’s left child becomes node 3 and its right child becomes node 1. Returnroot, which is node 2.Resuming Line 6 of invertTree(4): The
invertTree(2)call returns node 2, which is assigned toinverted_left_subtree.The process continues similarly for the right subtree of node 4 (i.e.,
invertTree(7)) and finally for swapping the left and right children of the root itself.
This step-by-step explanation keeps track of the status of the root, inverted_left_subtree, and inverted_right_subtree variables at each step of the function call. The recursive nature of the function allows us to keep track of the state at each level of recursion, and the function modifies and returns these variables accordingly.
Line 2:
invertTreeis first called on the root node, which is 4. So,root=4.Line 3: We check if
rootisNone, which is not, so we continue to the next line.Line 6: We call
invertTreeonroot.left(node 2). We pause the current execution (for root=4) and begin executinginvertTreeforroot=2.Line 3: For
root=2, it is also notNone, so we continue.Line 6: Now we call
invertTreeonroot.left(node 1). This will pause the execution forroot=2and begin executinginvertTreeforroot=1.Line 3: For
root=1, we check if it isNone, which it’s not.Line 6: We call
invertTreeonroot.leftof node 1, which isNone. This starts a new execution forroot=None.Line 3: For
root=None, this condition is met, and so we returnNonein Line 4.Line 7: Back in
invertTree(1), we’re trying to executeinvertTreeonroot.rightof node 1, which is alsoNone. This starts a new execution and immediately returnsNoneas well.Line 9 and 10: Since
root.leftandroot.rightfor node 1 are bothNone, swapping them does nothing. The functioninvertTree(1)then returns node 1, which is assigned toinverted_left_subtreein theinvertTree(2)call.Line 7: Back in the
invertTree(2)call, we now callinvertTree(root.right), which callsinvertTreeon node 3. This process is similar to the process for node 1, andinvertTree(3)will return node 3, which is assigned toinverted_right_subtree.Line 9 and 10: Now, in the
invertTree(2)call, we haveinverted_left_subtree = Node(1)andinverted_right_subtree = Node(3), we swaproot.leftandroot.right, so node 2’s left child becomes node 3 and its right child becomes node 1. We then return node 2.This process continues in a similar fashion for the right subtree of the original root (node 7) and finally for the root itself (node 4).
By the end of these steps, your tree is fully inverted.
Remember that each time we call invertTree, we start a new “execution context”. That’s why we’re able to pause at Line 6 or 7 and resume after the function call finishes. This is a key aspect of how recursion works.