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

Pythonでプレオーダートラバーサルから二分探索木(BST)を構築する方法

与えられた先行順走査(プレオーダートラバーサル)に一致する二分探索木を作成することを考えます。例えば、先行順走査が [8,5,1,7,10,12] の場合、出力は [8,5,10,1,7,null,12] となり、構築される木は以下のようになります。

Pythonでプレオーダートラバーサルから二分探索木(BST)を構築する方法

アルゴリズムの考え方

先行順走査では、最初の要素が必ず根(ルート)になります。また、二分探索木の性質上、あるノードより小さい値は左部分木へ、大きい値は右部分木へ配置されます。この性質を利用し、スタックを使って祖先ノードを管理しながら木を組み立てていくのがポイントです。

手順

  • root := 先行順リストの0番目の要素をノードとして作成
  • stack := 空のスタックを用意し、rootをプッシュ
  • 先行順リストの2番目以降の各要素 i について以下を繰り返す
    • i := 値 i を持つ新しいノードを作成
    • i の値がスタックトップの値より小さい場合
      • スタックトップノードの左の子 := i
      • i をスタックにプッシュ
    • そうでない場合
      • スタックが空でなく、スタックトップの値が i の値より小さい間、以下を繰り返す
        • last := スタックトップのノード
        • スタックからポップ
      • last ノードの右の子 := i
      • i をスタックにプッシュ
  • root を返す

Pythonでの実装例

理解を深めるために、以下の実装を見てみましょう。

class Solution(object):
   def bstFromPreorder(self, preorder):
      """
      :type preorder: List[int]
      :rtype: TreeNode
      """
      root = TreeNode(preorder[0])
      stack = [root]
      for i in preorder[1:]:
         i = TreeNode(i)
         if i.val<stack[-1].val:
            stack[-1].left = i
            stack.append(i)
         else:
            while stack and stack[-1].val<i.val:
               last = stack.pop(-1)
            last.right = i
            stack.append(i)
      return root

入力例

[8,5,1,7,10,12]

出力例

[8,5,10,1,7,null,12]

計算量について

このアルゴリズムでは、各ノードは最大でも一度プッシュされ、一度ポップされるため、時間計算量は O(n)、空間計算量もスタックの深さ分の O(n) となります。先行順走査の特性とBSTの性質を組み合わせることで、非常に効率的に木を再構築できるのが特徴です。

  1. 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 の両方を子孫に持ち、それより

  2. Pythonでソート済み配列を高さバランスの二分探索木に変換する方法

    ソートされた配列 A が与えられたとき、そこから高さバランスの取れた二分探索木(BST)を生成することを考えます。ここで「高さバランスの取れた二分木」とは、すべてのノードにおいて、左右の部分木の深さの差が常に1以下であるような二分木のことを指します。例として、配列が [-10, -3, 0, 5, 9] の場合、出力の一例は [0, -3, 9, -10, null, 5] のようになります。解法のアプローチこの問題は、配列の中央要素をルートに選ぶというシンプルな発想で解くことができます。具体的な手順は以下の通りです。配列 A が空の場合は、Null(None)を返します。配列の中央の要素を見