Pythonで二分木の各ノードを左右の部分木の合計値で更新するプログラム
問題の概要
二分木が与えられたとき、各ノードの値を「自分自身の値 + 左右の部分木の合計」に置き換えた木を求めることを考えます。つまり、木を葉から根へ(ポストオーダー)たどりながら、すべてのノードを部分木の総和で更新していく処理です。
例えば、次のような二分木が入力として与えられたとします。

この場合、出力は次のようになります。

アルゴリズム
この問題は再帰を使ったポストオーダー走査でシンプルに解けます。手順は以下の通りです。
- 関数
tree_sum()を定義します。引数として木のルートを受け取ります。 - ルートが
None(空)の場合は0を返します。 - そうでなければ、ルートの値を次のように更新します。
root.data = tree_sum(root.left) + tree_sum(root.right) + root.data - 更新後の
root.dataを呼び出し元に返します。 - メイン側では
tree_sum(root)を実行した後、更新済みのrootを返します。
Pythonでの実装例
class TreeNode:
def __init__(self, data, left=None, right=None):
self.data = data
self.left = left
self.right = right
def inorder(root):
if root:
inorder(root.left)
print(root.data, end=', ')
inorder(root.right)
class Solution:
def solve(self, root):
def tree_sum(root: TreeNode):
if root is None:
return 0
root.data = tree_sum(root.left) + tree_sum(root.right) + root.data
return root.data
tree_sum(root)
return root
ob = Solution()
root = TreeNode(2)
root.left = TreeNode(3)
root.right = TreeNode(4)
root.left.left = TreeNode(9)
root.left.right = TreeNode(7)
ob.solve(root)
inorder(root)
入力
root = TreeNode(2) root.left = TreeNode(3) root.right = TreeNode(4) root.left.left = TreeNode(9) root.left.right = TreeNode(7)
出力
9, 19, 7, 25, 4,
動作の解説
コードの流れを具体的に見てみましょう。
- 葉ノード 9 と 7 は子を持たないため、値は変わりません。
- ノード 3 は
3 + 9 + 7 = 19に更新されます。 - ノード 4 も葉なので
4のままです。 - ルート 2 は
2 + 19 + 4 = 25に更新されます。
最後に inorder()(中間順走査)で表示すると、「9, 19, 7, 25, 4,」という結果が得られます。
計算量
- 時間計算量: O(n) ― 各ノードをちょうど1回ずつ訪問するためです。
- 空間計算量: O(h) ― 再帰呼び出しによるスタック消費で、h は木の高さです。木が偏って鎖状になっている場合は O(n) になります。
-
Pythonで二分木のルートからリーフへのパスの最大合計を求めるプログラム
問題概要 二分木(バイナリツリー)が与えられたとき、ルートノードからリーフノードへ至る任意のパスの中で、合計値が最大となるものを求める必要があります。 例として、次のような二分木が入力された場合を考えてみましょう。 この場合の出力は 29 になります。ルートから「5 → 9 → 7 → 8」というパスを辿ったときの合計が 29 となるためです。 解法のアプローチ この問題は、深さ優先探索(DFS)を用いて、ルートから各リーフまでのすべてのパスを再帰的に走査することで解けます。具体的な手順は以下のとおりです。 walk() 関数を定義します。引数として現在のノード node と、そこまでの
-
Pythonで左右の部分木が同一となる最大の部分木を見つける方法
問題の概要二分木が与えられたとき、左の部分木と右の部分木が完全に一致している最大の部分木を見つけることを考えます。望ましい計算量は O(n) です。例えば、次のような二分木が入力として与えられた場合を考えてみましょう。この場合、出力は次のようになります。解法のアプローチこの問題を解くためには、木をボトムアップ(下から上へ)に走査し、各ノードについて「そのノードを根とする部分木の構造を表す文字列(エンコード)」を作成します。そして、左部分木のエンコードと右部分木のエンコードが一致していれば、そのノードは「左右が同一の部分木」の根であると判断できます。具体的な手順は以下の通りです。solve()