🚀

よわよわエンジニアが解く226. Invert Binary Tree

2024/03/17に公開
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
class Solution:
    def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        if root is None:
            return None
        
        root.left , root.right = root.right, root.left
        self.invertTree(root.left)
        self.invertTree(root.right)

        return root

このように解くらしい。
全くわからなかったため、再帰処理から学ぶことにした。

再帰処理とは、、自分自身を呼び出す処理が含まれる関数。終了条件を書かないと大変なことになる。
処理結果は終端から積み上げる。

以下は1からnまでの整数を合計する処理。0が返されると前の関数に戻り、計算結果が積み上げられていく。

def total(n):
    if n < 1:
        return 0
    return n + total(n - 1)

print(total(5))
# 5 + total(4) 10が返されるので10+5
# 4 + total(3) 6が返されるので6+4
# 3 + total(2) 3が返されるので3+3
# 2 + total(1) 1が返されるので1+2
# 1 + total(0) 0が返されるので0+1
# 0

以下はnの階乗を求める処理。1が返されると前の関数に戻り、計算結果が積み上げられていく。
0を返すと0になるので注意。

def factorial(n):
    if n < 1:
        return 1
    return n * factorial(n - 1)

print(factorial(3))
# 3 * total(2) 2が返されるので3*2
# 2 * total(1) 1が返されるので2*1
# 1 * total(0) 1が返されるので1*1
# 0

上記を踏まえて考えると、入力が[4,2,7,1,3,6,9]の場合の処理の流れは、
ルートノード(4): 左右の子ノードを反転(左: 7, 右: 2)し、再帰的に左右の子ノードに対して処理を行う。
左子ノード(7): 左右の子ノードを反転(左: 9, 右: 6)。9と6に対して再帰処理を行うが、両方とも子ノードがない(None)ため、そのまま戻る。
右子ノード(2): 左右の子ノードを反転(左: 3, 右: 1)。3と1に対して再帰処理を行うが、これらも両方子ノードがない(None)ため、そのまま戻る。

再帰関数では一度実行した処理が再度実行されることはない。
9と6の再帰処理から7のノードに戻った時に、もう一度左から見にいくことはないため、全てのノードを走破できる。

    4
   / \
  7   2
 / \ / \
9  6 3 1

例えば以下のような探索処理があった場合は、左端まで探して上のノードに戻った時に、また左端から探すということは行わず、右の子ノードを探しにいく。

left_result = find_node(root.left, value)
if left_result is not None:
    return left_result

return find_node(root.right, value)

Discussion