アルゴリズム概要

問題

二分探索木(BST)において、ちょうど2つのノードの値が誤って入れ替わっている。 木の構造を変更せずに、値のスワップのみでBSTを修復する。

入出力例

入力: root = [3,1,4,null,null,2]  (3と2が入れ替わっている)
出力: [2,1,4,null,null,3]

      3*              2
     / \    →       / \
    1   4          1   4
       /              /
      2*             3

戦略

違反パターン

ケース 正しい順序 入れ替え後 違反回数
隣接ノード [1,2,3,4] [1,3,2,4] 1回 (3>2)
非隣接ノード [1,2,3,4] [1,4,3,2] 2回 (4>3, 3>2)

ステップバイステップ解説

Python実装

class Solution:
    def recoverTree(self, root: Optional[TreeNode]) -> None:
        """
        BST修復(再帰版)
        Time: O(n), Space: O(h)
        """
        self.first = self.second = self.prev = None
        self._inorder(root)
        # 値のスワップ
        self.first.val, self.second.val = self.second.val, self.first.val

    def _inorder(self, node: Optional[TreeNode]) -> None:
        if not node:
            return

        # 左部分木を走査
        self._inorder(node.left)

        # 違反チェック: prev > curr はBST違反
        if self.prev and self.prev.val > node.val:
            if not self.first:
                self.first = self.prev  # 最初の違反
            self.second = node  # 常に更新

        self.prev = node

        # 右部分木を走査
        self._inorder(node.right)

フローチャート

viewBox="0 0 700 850" style="max-width: 100%; height: auto" role="img" aria-label="Recover BST flowchart" > 開始 first, second, prev = None node is None? はい return いいえ inorder(node.left) prev and prev.val > node.val? はい first? None first = prev second = node いいえ prev = node inorder(node.right) 再帰 終了

フローの説明:

1初期化: first, second, prev を None に設定

2ノードがNoneなら即座にreturn(基底条件)

3左部分木を再帰的に走査(中順走査の「左」)

4違反チェック: prev.val > node.val ならBST違反

5最初の違反で first = prev を設定

6常に second = node を更新(隣接/非隣接両対応)

7prev を現在のノードに更新

8右部分木を再帰的に走査(中順走査の「右」)

9全走査完了後、first と second の値をスワップして修復完了

計算量分析

方式 時間計算量 空間計算量 特徴
再帰版 O(n) O(h) 最も可読性が高い
Morris版 O(n) O(1) Follow-up要件を満たす
配列保存版 O(n) O(n) 理解しやすい

詳細分析