アルゴリズム概要

中順走査
左 → 根 → 右
O(N)
時間計算量
O(N)
空間計算量
反復スタック
再帰なし実装

📌 問題要約

二分木の根ノード root が与えられる。 中順走査(左→根→右) でノードの値を収集し、リストとして返す。
Follow-up: 再帰を使わない反復解を実装せよ。

Input: root = [1, null, 2, 3]
Output: [1, 3, 2]

📏 制約

  • 🔢 ノード数 N: 0 ≤ N ≤ 100
  • 🔢 値の範囲: −100 ≤ val ≤ 100
  • ⚠️ Python再帰上限: デフォルト 1,000(N>1000で危険)
  • ✅ 反復実装でスタックオーバーフロー回避

ステップ解説

実装コード

from __future__ import annotations
from typing import Optional


# Definition for a binary tree node.
class TreeNode:
    def __init__(
        self,
        val: int = 0,
        left: Optional["TreeNode"] = None,
        right: Optional["TreeNode"] = None,
    ) -> None:
        self.val = val
        self.left = left
        self.right = right


class Solution:
    """
    LeetCode 94 - Binary Tree Inorder Traversal
    中順走査(左→根→右)を明示スタックによる反復で実装。

    Time:  O(N) - 全ノードを一度だけ訪問
    Space: O(N) - 明示スタックの最大深さ(最悪: 左偏木で N)
    """

    def inorderTraversal(self, root: Optional[TreeNode]) -> list[int]:
        # ── ガード: 空木は即座に空リストを返す
        if root is None:
            return []

        result: list[int] = []          # 中順走査の結果
        stack: list[TreeNode] = []      # 明示スタック(非 None のみ格納)
        cur: Optional[TreeNode] = root  # 現在注目しているノード

        while cur is not None or stack:

            # Ph1: 左端まで潜りながらスタックに積む
            while cur is not None:
                stack.append(cur)   # 右・自身は後回し
                cur = cur.left      # 左へ進む

            # Ph2: スタック top を取り出して訪問
            node: TreeNode = stack.pop()
            result.append(node.val)  # ← 中順で値を記録

            # Ph3: 右部分木へカーソルを移す
            cur = node.right  # None なら次ループで即 Ph2 へ

        return result

処理フローチャート

開始 初期化 result=[] stack=[] cur=root cur != None または stack 非空? No Yes Ph1: cur != None? (左端まで潜る) Yes スタックに積む stack.append(cur) cur = cur.left 繰り返し No Ph2: スタックから取り出して訪問 node = stack.pop() result.append(node.val) ← 中順で記録 Ph3: 右部分木へ移動 cur = node.right ループ継続 結果を返す return result # list[int] 終了

フローの説明:
1. 初期化: result・stack・curを初期設定する。
2. ループ条件: curが非Noneまたはstackが空でない間、3フェーズを繰り返す。
3. Ph1(緑): curが非Noneの間、左端まで潜りながらスタックに積む(ループバック=紫矢印)。
4. Ph2(青): スタックからpopし、val を結果リストに中順で記録する。
5. Ph3(紫): cur = node.right に移動し、ループ条件へ戻る(紫矢印)。
6. 終了(赤): curとstackが共に空になったら結果を返す。

計算量分析

O(N)
時間計算量

全ノードをスタックに push 1回・pop 1回の合計 2N 操作。定数倍を無視すると O(N)。

O(N)
空間計算量

明示スタックの最大深さ。最悪ケースは N ノードが全て左に偏った木(スタック深さ = N)。

アプローチ 時間 空間 可読性 安全性
✅ 反復(明示スタック) O(N) O(N) ★★★
再帰 DFS O(N) O(N) ★★★ △ ※
Morris Traversal O(N) O(1) ★☆☆ △ 副作用

※ Python デフォルト再帰上限 1,000 でスタックオーバーフローリスクあり