Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonで二分木の最小共通祖先(LCA)を求めるアルゴリズムと実装例

はじめに

二分木と2つの数値 ab が与えられたとき、ab を子孫として持つ最も深いノード(最小共通祖先:LCA)の値を求める問題を考えてみましょう。

ここで重要なポイントは、「あるノードはそれ自身の子孫にもなり得る」という点です。つまり、片方のノードがもう片方の祖先である場合、そのノード自体が答えになります。

以下のような二分木を考えます。

Pythonで二分木の最小共通祖先(LCA)を求めるアルゴリズムと実装例

このとき、a = 6b = 2 とすると、出力は 4 になります。値4のノードが、6と2の両方を子孫として持つ最も深いノードだからです。

解法のアプローチ

この問題は再帰を使って効率的に解くことができます。手順は以下の通りです。

  • solve() メソッドを定義し、ルートノード root と探索対象の値 ab を引数として受け取ります。
  • rootnull(None)の場合は -1 を返します。
  • root の値が a または b のいずれかと一致する場合は、その値を返します。
  • 左部分木に対して left = solve(root.left, a, b) を実行します。
  • 右部分木に対して right = solve(root.right, a, b) を実行します。
  • leftright両方-1 でない場合、現在のノードが共通祖先であるため、root の値を返します。
  • 片方だけが見つかっている場合は、-1 でない方の値を返します。
  • メイン処理から solve(root) を呼び出します。

Pythonでの実装例

実際のコードを見てみましょう。

class TreeNode:
    def __init__(self, val, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def solve(self, root, a, b):
        if not root:
            return -1
        if root.val in (a, b):
            return root.val
        left = self.solve(root.left, a, b)
        right = self.solve(root.right, a, b)
        if -1 not in (left, right):
            return root.val
        return left if left != -1 else right

ob = Solution()
root = TreeNode(3)
root.left = TreeNode(10)
root.right = TreeNode(4)
root.right.left = TreeNode(8)
root.right.right = TreeNode(2)
root.right.left.left = TreeNode(6)
print(ob.solve(root, 6, 2))

入力

root = TreeNode(3)
root.left = TreeNode(10)
root.right = TreeNode(4)
root.right.left = TreeNode(8)
root.right.right = TreeNode(2)
root.right.left.left = TreeNode(6)
6, 2

出力

4

コードの解説

このアルゴリズムの動作を簡単に整理します。

  • ベースケース: ノードが存在しない場合は -1 を返し、対象の値が見つかった時点でその値を返します。
  • 後処理(ボトムアップ): 再帰呼び出しの結果を左右それぞれから受け取り、両側で異なる対象が見つかったノードが最小共通祖先となります。
  • 計算量: 各ノードを一度だけ訪問するため、時間計算量は O(n)、再帰の深さによる空間計算量は木の高さに依存し、最悪で O(n) です。

このように、再帰的な後順走査(post-order traversal)を利用することで、二分木の最小共通祖先を簡潔に求めることができます。

  1. Pythonで二分木の最小共通祖先(LCA)を求める方法

    二分木が与えられたとき、指定した2つのノードの最小共通祖先(Lowest Common Ancestor:LCA)を求める問題を考えてみましょう。ノード p と q の LCA とは、p と q の両方を子孫として持つノードの中で、最も深い位置にあるノードのことです。 例えば、二分木が [3,5,1,6,2,0,8,null,null,7,4] という形式で表されている場合、木の構造は次のようになります。 この場合、ノード 5 と ノード 1 の LCA は 3 となります。 解法のアプローチ この問題は、再帰を使って次の手順で解くことができます。 木が空(None)の場合は、None

  2. Pythonで二分探索木の最小共通祖先(LCA)を求める方法【再帰アルゴリズム解説】

    最小共通祖先(LCA)とは二分探索木(Binary Search Tree)が与えられたとき、指定された2つのノードの最小共通祖先(Lowest Common Ancestor:LCA)を求める問題を考えてみましょう。ノード p と q の LCA とは、「p と q の両方を子孫として持つノードの中で、最も深い位置にあるノード」のことです。例えば、次のような二分木があるとします。[6, 2, 8, 0, 4, 7, 9, null, null, 3, 5]この木は以下のような構造になります。この場合、2 と 8 の LCA は 6 となります。6 は 2 と 8 の両方を子孫に持ち、それより