Pythonで二分木から「子を1つだけ持つノード」をすべて削除する方法
問題の概要
二分木のルートが与えられたとき、子を1つしか持たないノード(左右どちらか片方の子だけを持つノード)をすべて木から取り除くことを考えます。子を2つ持つノードや、子をまったく持たない葉ノードはそのまま残します。
例えば、次のような二分木が入力として与えられたとします。

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

解法のアプローチ
この問題は再帰処理を使うことでシンプルに解けます。片方の子しかないノードを見つけたら、そのノードをスキップして子を直接親につなぎ替えるイメージです。具体的には、以下の手順に従います。
solve() というメソッドを定義する。引数として木のルートを受け取る
root が null(None)の場合は、そのまま root を返す
root の左の子も右の子も存在しない(葉ノード)場合は、root を返す
root の左の子が存在しない場合は、solve(右の子) の結果を返す
root の右の子が存在しない場合は、solve(左の子) の結果を返す
root.left := solve(root.left) として左部分木を再帰的に処理する
root.right := solve(root.right) として右部分木を再帰的に処理する
最後に root を返す
実装例(Pythonコード)
class TreeNode: def __init__(self, data, left = None, right = None): self.data = data self.left = left self.right = right def print_tree(root): if root is not None: print_tree(root.left) print(root.data, end = ', ') print_tree(root.right) class Solution: def solve(self, root): if not root: return root if not root.left and not root.right: return root if not root.left: return self.solve(root.right) if not root.right: return self.solve(root.left) root.left = self.solve(root.left) root.right = self.solve(root.right) return root ob = Solution() root = TreeNode(1) root.left = TreeNode(2) root.right = TreeNode(3) root.left.left = TreeNode(4) root.right.right = TreeNode(5) root.left.left.right = TreeNode(6) root.right.right.left = TreeNode(7) root.right.right.right = TreeNode(8) res = ob.solve(root) print_tree(res)
入力
root = TreeNode(1) root.left = TreeNode(2) root.right = TreeNode(3) root.left.left = TreeNode(4) root.right.right = TreeNode(5) root.left.left.right = TreeNode(6) root.right.right.left = TreeNode(7) root.right.right.right = TreeNode(8)
出力
6, 1, 7, 5, 8,
コードのポイント
このアルゴリズムでは、solve() メソッドが各ノードに対して再帰的に呼び出されます。重要なのは、片方の子しか持たないノードに到達した時点で、そのノード自体を返さずに、存在する側の子の再帰結果を返すという点です。これにより、該当ノードは親から切り離され、事実上削除されたことになります。
処理の流れを整理すると以下の通りです。
ノードが null なら何もせず終了(ベースケース)
葉ノードなら削除対象ではないためそのまま残す
子が1つだけあるノードは、その子以降の部分木の処理結果で置き換える
子が2つあるノードは、左右それぞれの部分木を再帰的に処理してから残す
この手法により、時間計算量は木のノード数を N とすると O(N) で済みます。すべてのノードを一度ずつ訪問するだけでよいため、効率的な解法と言えます。
-
Pythonで二分木から偶数の値を持つ葉ノードをすべて削除する方法
二分木が与えられたとき、値が偶数であるすべての葉(リーフ)ノードを繰り返し削除する問題を考えてみましょう。削除を続けた結果、根ノードだけが残り、その値が偶数であった場合は、根ノードも併せて削除します。例えば、入力が次のような二分木だったとします。この場合、出力は次のようになります。解き方のアプローチこの問題は、後順(post-order)に近い再帰処理を使うことでシンプルに解けます。子ノードを先に処理し、その結果を受けて親ノードを判定する流れです。具体的には以下の手順に従います。関数 solve() を定義します。引数としてルートノードを受け取ります。root が null(None)の場合は
-
Pythonで二分探索木(BST)から指定範囲外のノードをすべて削除する方法
問題の概要二分探索木(BST)と2つの値 low、high が与えられたとき、[low, high] の範囲(境界値を含む)に該当しないノードをすべて木から削除するプログラムを作成します。例として、次のようなBSTを考えてみましょう。ここで low = 7、high = 10 とした場合、範囲外のノード(5 や 1 など)が削除され、出力は次のようになります。解法のアプローチこの問題は再帰を利用することで簡潔に解くことができます。手順は以下の通りです。関数 solve() を定義します。引数は root(現在のノード)、low、high の3つです。root が null(空)の場合は何もせず