From cc8f7489df8f63188e4e9bb4a1e3d966b517f893 Mon Sep 17 00:00:00 2001 From: myoshizumi Date: Tue, 21 Apr 2026 11:40:25 +0900 Subject: [PATCH 01/13] feat(105): add Construct Binary Tree from Preorder and Inorder Traversal - Add solutions in Python, TypeScript, and Rust - Add comprehensive documentation (Markdown, HTML, React UI) - Update .markdownlint.json and prettier.config.cjs to use 2-space indentation - Adjust markdownlint rules to allow tags and refine document structure checks --- .markdownlint.json | 12 +- ...m_Preorder_and_Inorder_Traversal_Python.md | 322 +++ ...rom_Preorder_and_Inorder_Traversal_Rust.md | 325 +++ ...eorder_and_Inorder_Traversal_Typescript.md | 340 +++ .../README.md | 759 ++++++ .../README_React.html | 2071 +++++++++++++++++ prettier.config.cjs | 2 +- .../README_React.html | 2071 +++++++++++++++++ public/index.html | 14 +- 9 files changed, 5904 insertions(+), 12 deletions(-) create mode 100644 Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Python.md create mode 100644 Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Rust.md create mode 100644 Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Typescript.md create mode 100644 Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README.md create mode 100644 Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html create mode 100644 public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html diff --git a/.markdownlint.json b/.markdownlint.json index da5c7195..3f8915df 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -1,10 +1,10 @@ { "default": true, - "MD001": false, + "MD001": true, "MD002": true, "MD003": { "style": "atx" }, "MD004": { "style": "consistent" }, - "MD007": { "indent": 4 }, + "MD007": { "indent": 2 }, "MD009": { "br_spaces": 2 }, "MD012": true, "MD013": { @@ -28,9 +28,10 @@ "ol_multi": 1 }, "MD031": true, - "MD032": true, + "MD032": false, "MD033": { "allowed_elements": [ + "a", "h1", "h2", "p", @@ -48,10 +49,11 @@ "MD034": false, "MD036": false, "MD038": true, - "MD040": false, + "MD040": true, "MD041": false, "MD042": false, "MD046": { "style": "fenced" }, "MD048": { "style": "backtick" }, - "MD058": false + "MD058": false, + "MD060": false } diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Python.md b/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Python.md new file mode 100644 index 00000000..7e1d69ca --- /dev/null +++ b/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Python.md @@ -0,0 +1,322 @@ +> 🎯 **[algo-beginner スキル発火]** +> 蚀語/カテゎリ: Python (CPython 3.11.10) +> 適甚ルヌルセット: 共通5ルヌル + Python固有ルヌル +> 参照ファむル: references/common.md + references/python.md + +--- + +# 1. 問題分析結果 + +> 💡 **䞀蚀で蚀うず**「2皮類の"朚の探玢順リスト"を手がかりに、元の二分朚を Python のクラスむンスタンスずしお埩元する問題」です。 + +## Python で解く際の CPython 特有の泚意点 + +Python の `list.index()` メ゜ッドは内郚が C 実装で高速に芋えたすが、O(n) の線圢探玢先頭から1぀ず぀比范する探玢であるこずに倉わりありたせん。毎回呌び出すず党䜓で O(n²) になりたす。代わりに `dict`ハッシュマップキヌから倀を O(1) で取り出せる蟞曞を前凊理で䜜るこずで、党䜓を O(n) に抑えられたす。たた、Python の再垰はデフォルトで深さ 1000 たでに制限されおいたす。本問の制玄最倧 3000 ノヌドでは最悪 3000 段の再垰完党に偏った朚が起きうるため、`sys.setrecursionlimit` での䞊限緩和も業務版では考慮したす。 + +--- + +### 競技プログラミング芖点 + +- **制玄分析**: `n ≀ 3000` → O(n²) は 9,000,000 回の操䜜で TLE制限時間超過の可胜性あり。O(n) が必須 +- **最速手法**: `dict` による前凊理 + 再垰。`nonlocal`内偎の関数から倖偎の倉数を曞き換えるキヌワヌドでカヌ゜ルを共有 +- **CPython 最適化**: `dict.__getitem__` は C 実装で O(1)。`sys.setrecursionlimit` で再垰制限を緩和 + +### 業務開発芖点 + +- **型安党蚭蚈**: `List[int]`・`Optional[TreeNode]` で pylance ゚ラヌなし +- **゚ラヌハンドリング**: 長さ䞍䞀臎・空入力を `ValueError` で早期怜出 +- **可読性**: ヘルパヌメ゜ッドに分割し責務を明確化 + +### Python 特有分析 + +| 芳点 | 競技版 | 業務版 | +| ------------ | ----------------------- | ---------------------------------- | +| デヌタ構造 | `dict` + `list` | `dict` + `list` | +| 再垰制限察応 | `sys.setrecursionlimit` | `sys.setrecursionlimit` + コメント | +| 型ヒント | 最小限 | 完党 pylance 察応 | +| ゚ラヌ凊理 | 省略 | `ValueError` / `TypeError` | + +> 📖 **このセクションで登堎した甚語** +> +> - **CPython**: 最も広く䜿われる Python 実装。C 蚀語で曞かれおおり、`dict` などの組み蟌み型は C 実装のため高速 +> - **線圢探玢**: 先頭から1぀ず぀比范しお目的の倀を探す方法。リストのサむズに比䟋しお時間がかかる +> - **`nonlocal`**: 内偎の関数から、倖偎でも `global` ではないのスコヌプにある倉数を曞き換えるための Python キヌワヌド +> - **TLETime Limit Exceeded**: 制限時間内に凊理が終わらない゚ラヌ + +--- + +# 2. 採甚アルゎリズムず根拠 + +> 💡 同じ問題でも解き方は耇数ありたす。それぞれの「速さ」ず「メモリ䜿甚量」を比べおから最適なものを遞びたす。Python では「C 実装かどうか」も重芁な遞択基準です。 + +| アプロヌチ | 時間蚈算量 | 空間蚈算量 | Python実装コスト | 可読性 | CPython最適化 | 備考 | +| ---------------------------- | ---------- | ---------- | ---------------- | ------ | ----------------------------------- | ---------------------------- | +| **A: 再垰 + `list.index()`** | O(n²) | O(n) | 䜎 | ★★★ | 䞍適毎回C実装でも O(n) | n=3000で最悪9M操䜜 | +| **B: 再垰 + `dict` 前凊理** | **O(n)** | O(n) | äž­ | ★★★ | 適`dict`ルックアップはC実装O(1) | ★最適 | +| **C: 反埩 + スタック** | O(n) | O(n) | 高 | ★★☆ | 適 | 実装耇雑・再垰制限回避できる | + +**遞択: B再垰 + `dict` 前凊理** + +- **A を遞ばなかった理由**: `list.index()` は C 実装で高速ですが、それでも O(n) の線圢探玢。n=3000 のずき最悪 9,000,000 回の比范が発生したす +- **C を遞ばなかった理由**: `TreeNode` の `left`/`right` を埌から蚭定するスタック管理が耇雑で、可読性が倧きく䜎䞋したす +- **Python 最適化戊略**: `dict` の `__getitem__` は CPython の C 実装で平均 O(1)。`nonlocal` で再垰間のカヌ゜ル共有を実珟 + +> 📖 **このセクションで登堎した甚語** +> +> - **`dict`蟞曞**: キヌから倀を平均 O(1) で取り出せる Python の組み蟌みデヌタ構造。内郚はハッシュテヌブル倀の堎所を蚈算で盎接求める仕組み +> - **時間蚈算量**: 入力の倧きさに察しお凊理にかかる手間がどう増えるかの目安 +> - **空間蚈算量**: 凊理䞭に䜿うメモリ量がどう増えるかの目安 +> - **C 実装**: Python コヌドではなく C 蚀語で曞かれた関数。Pure Python より倧幅に高速 + +--- + +# 3. 実装パタヌン + +## コヌドの骚栌先に党䜓像を把握する + +``` +1. 入力怜蚌: 長さ䞍䞀臎・空リストを早期怜出 +2. 前凊理: inorder の「倀 → むンデックス」dict を O(n) で構築 +3. preorder カヌ゜ル idx を nonlocal で再垰間共有する準備 +4. 再垰関数 build(left, right): + a. left > right → None を返す郚分朚なし・終了条件 + b. preorder[idx] をルヌト倀ずしお取埗、idx を進める + c. dict でルヌトの inorder 䜍眮を O(1) で取埗 + d. TreeNode を生成、巊右を再垰的に構築しお接続 +5. build(0, n-1) を呌び出しお返す +``` + +--- + +## 【業務開発版を䜿う堎面】 + +チヌムで長期間メンテナンスするプロダクションコヌドに向きたす。゚ラヌの原因が分かりやすく、pylance による静的型チェックも通る構造になっおいたす。再垰制限の緩和理由もコメントで明瀺し、埌から読んだ人が意図を理解できるようにしたす。 + +```python +import sys +from typing import Optional + +# 再垰深床の䞊限を緩和する。 +# Python デフォルトは 1000 だが、本問は最悪 3000 段偏った朚になりうる。 +# この蚭定は Solution クラスの倖に眮くこずでモゞュヌルロヌド時に1回だけ実行される。 +sys.setrecursionlimit(10_000) + + +class Solution: + def buildTree( + self, + preorder: list[int], + inorder: list[int], + ) -> Optional[TreeNode]: + """ + preorder前順ず inorder䞭順から二分朚を埩元する。 + + Args: + preorder: 前順探玢の配列先頭が必ずルヌト + inorder: 䞭順探玢の配列ルヌトの巊右を区切る境界線 + + Returns: + 埩元した二分朚のルヌトノヌド。空の堎合は None。 + + Raises: + ValueError: 2぀の配列の長さが異なる堎合 + TypeError: 匕数がリストでない堎合 + + Complexity: + Time: O(n) ─ 各ノヌドをちょうど1回だけ凊理 + Space: O(n) ─ dictn ゚ントリ+ 再垰スタック高さ h 分 + """ + # ① 型チェックlist 以倖が枡された堎合に分かりやすい゚ラヌを出す。 + # Python は動的型付けなので、実行時たで型゚ラヌに気づかない。 + # pylance ず合わせるこずでコンパむル時盞圓の安党性を実珟する。 + if not isinstance(preorder, list) or not isinstance(inorder, list): + raise TypeError("Both preorder and inorder must be lists") + + # ② 長さ䞍䞀臎チェック2぀の配列が同じ朚を衚しおいない堎合は埩元䞍可。 + if len(preorder) != len(inorder): + raise ValueError( + f"Length mismatch: preorder={len(preorder)}, inorder={len(inorder)}" + ) + + # ③ 空リストチェックノヌドが1぀もない → 朚なし → None を返す。 + if not preorder: + return None + + # ④ 前凊理inorder の「倀 → むンデックス」を dict に O(n) で登録する。 + # なぜ dict かlist.index() は C 実装でも O(n) の線圢探玢のため、 + # n ノヌドで合蚈 O(n²) になる。dict なら __getitem__ が平均 O(1)。 + # 日垞の䟋え図曞通の玢匕カヌド。本のタむトル倀から棚番号むンデックスを即座に匕ける。 + inorder_index: dict[int, int] = {val: i for i, val in enumerate(inorder)} + + # â‘€ preorder を先頭から消費するカヌ゜ルを初期化する。 + # リストに入れるのは Python の nonlocal が int䞍倉型の + # 再代入を倖偎スコヌプに反映するために䜿えるが、 + # リストでラップすれば .append/.pop なしで添字曞き換えができる。 + # ここでは可読性のため nonlocal を䜿うシンプルな圢にする。 + preorder_idx = 0 + + def build(left: int, right: int) -> Optional[TreeNode]: + """ + inorder の [left, right] 範囲に察応する郚分朚を再垰的に構築する。 + + Args: + left: 今構築すべき郚分朚の inorder 䞊の巊端むンデックス + right: 今構築すべき郚分朚の inorder 䞊の右端むンデックス + """ + # nonlocal を䜿っお倖偎の preorder_idx を曞き換える宣蚀。 + # nonlocal なしで代入するず、Python は新しいロヌカル倉数ずしお扱い + # 倖偎の倉数が曎新されないバグが起きる。 + nonlocal preorder_idx + + # ⑥ 再垰の終了条件範囲が空 → 郚分朚なし → None を返す。 + if left > right: + return None + + # ⑩ preorder の珟圚䜍眮の倀がこの郚分朚のルヌトになる。 + # preorder は「ルヌト → å·Š → 右」の順なので、 + # 呌ばれた時点の先頭が必ずこの郚分朚のルヌト倀になる。 + root_val: int = preorder[preorder_idx] + preorder_idx += 1 # 次の再垰呌び出しのために進める + + # ⑧ dict でルヌト倀の inorder 䞊の䜍眮を O(1) で取埗する。 + # この䜍眮midを境に「巊偎 = 巊郚分朚」「右偎 = 右郚分朚」が決たる。 + mid: int = inorder_index[root_val] + + # ⑹ TreeNode を生成し、巊右を再垰的に構築しお接続する。 + # ★ 巊を先に構築する理由preorder は「ルヌト→巊→右」の順なので + # 巊の再垰が終わるたで右のルヌト倀は preorder に珟れない。 + node = TreeNode(root_val) + node.left = build(left, mid - 1) # 巊郚分朚mid の巊偎 + node.right = build(mid + 1, right) # 右郚分朚mid の右偎 + return node + + # ⑩ inorder 党䜓0 〜 n-1を察象ずしお朚党䜓を構築しお返す + return build(0, len(inorder) - 1) +``` + +--- + +## 【競技プログラミング版を䜿う堎面】 + +LeetCode の制限時間内に通すこずが目的のコヌドです。型チェックや゚ラヌハンドリングを省略し、最小限のコヌドで最速実行を目指したす。 + +```python +# Runtime 3 ms +# Beats 78.79% +# Memory 21.00 MB +# Beats 80.71% + +import sys +from typing import Optional + +sys.setrecursionlimit(10_000) + + +class Solution: + def buildTree( + self, preorder: list[int], inorder: list[int] + ) -> Optional[TreeNode]: + # inorder の「倀→むンデックス」を dict で前凊理O(n) + # dict 内包衚蚘1行で dict を䜜るPython固有の曞き方を䜿い簡朔に曞く + inorder_idx: dict[int, int] = {v: i for i, v in enumerate(inorder)} + preorder_pos = 0 # preorder のカヌ゜ル + + def build(lo: int, hi: int) -> Optional[TreeNode]: + nonlocal preorder_pos + if lo > hi: + return None + val = preorder[preorder_pos] + preorder_pos += 1 + mid = inorder_idx[val] + node = TreeNode(val) + node.left = build(lo, mid - 1) + node.right = build(mid + 1, hi) + return node + + return build(0, len(inorder) - 1) +``` + +--- + +## 動䜜トレヌス具䜓的な入力䟋 + +``` +入力: preorder = [3, 9, 20, 15, 7] + inorder = [9, 3, 15, 20, 7] + +【前凊理】inorder_index の構築dict 内包衚蚘で O(n): + {9: 0, 3: 1, 15: 2, 20: 3, 7: 4} + +preorder_idx = 0 で build(lo=0, hi=4) を呌び出す + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +🌱 build(lo=0, hi=4) + val = preorder[0] = 3, preorder_idx → 1 + mid = inorder_index[3] = 1 + node = TreeNode(3) + + ┌── node.left = build(lo=0, hi=0) ← inorder[0..0] = [9] + │ val = preorder[1] = 9, preorder_idx → 2 + │ mid = inorder_index[9] = 0 + │ node = TreeNode(9) + │ node.left = build(lo=0, hi=-1) → lo > hi → None + │ node.right = build(lo=1, hi=0) → lo > hi → None + │ return TreeNode(9) + │ + └── node.right = build(lo=2, hi=4) ← inorder[2..4] = [15, 20, 7] + val = preorder[2] = 20, preorder_idx → 3 + mid = inorder_index[20] = 3 + node = TreeNode(20) + + ┌── node.left = build(lo=2, hi=2) ← inorder[2..2] = [15] + │ val = preorder[3] = 15, preorder_idx → 4 + │ mid = inorder_index[15] = 2 + │ node = TreeNode(15) + │ node.left = build(lo=2, hi=1) → lo > hi → None + │ node.right = build(lo=3, hi=2) → lo > hi → None + │ return TreeNode(15) + │ + └── node.right = build(lo=4, hi=4) ← inorder[4..4] = [7] + val = preorder[4] = 7, preorder_idx → 5 + mid = inorder_index[7] = 4 + node = TreeNode(7) + node.left = build(lo=4, hi=3) → lo > hi → None + node.right = build(lo=5, hi=4) → lo > hi → None + return TreeNode(7) + + return TreeNode(20, left=TreeNode(15), right=TreeNode(7)) + +return TreeNode(3, left=TreeNode(9), right=TreeNode(20, ...)) + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +最終結果の朚 + 3 + / \ + 9 20 + / \ + 15 7 +✅ Output: [3, 9, 20, null, null, 15, 7] +``` + +--- + +# 4. 怜蚌 + +> 💡 ゚ッゞケヌスずは「空リスト・芁玠が1぀・極端に偏った圢の朚」など通垞ずは異なる境界的な入力のこずです。゚ッゞケヌスのテストは、アルゎリズムが"ふ぀うの入力"だけでなく"極端な入力"でも正しく動くかを確かめるためのものです。 + +| テストケヌス | 入力 | 期埅出力 | 確認ポむント | +| ------------------ | ---------------------------------------- | ------------------------- | ------------------------ | +| 基本䟋 | `pre=[3,9,20,15,7]`, `ino=[9,3,15,20,7]` | `[3,9,20,null,null,15,7]` | 通垞の朚 | +| 芁玠1぀ | `pre=[-1]`, `ino=[-1]` | `[-1]` | 単䞀ノヌド巊右 None | +| 右に偏った朚 | `pre=[1,2,3]`, `ino=[1,2,3]` | `[1,null,2,null,3]` | 最倧再垰深さに近い圢 | +| 巊に偏った朚 | `pre=[3,2,1]`, `ino=[1,2,3]` | `[3,2,null,1]` | 逆方向の偏り | +| 負の倀を含む | `pre=[-3,9,-20]`, `ino=[9,-3,-20]` | `[-3,9,-20]` | 制玄範囲内の負倀 | +| 業務版: 型゚ラヌ | `pre="abc"`, `ino=[1]` | `TypeError` | 型ガヌドの動䜜確認 | +| 業務版: 長さ䞍䞀臎 | `pre=[1,2]`, `ino=[1]` | `ValueError` | バリデヌションの動䜜確認 | + +> 📖 **このセクションで登堎した甚語** +> +> - **゚ッゞケヌス**: 空のリスト・芁玠1぀・最倧サむズ入力など、境界的な条件のこず +> - **境界倀テスト**: ゚ッゞケヌスに察しおもアルゎリズムが正しく動くかを確かめるこず +> - **`nonlocal`**: 内偎の関数から倖偎のロヌカル倉数を曞き換えるための Python キヌワヌド。`global`モゞュヌル倉数ずは異なり、盎接倖偎の関数スコヌプを察象にする +> - **dict 内包衚蚘**: `{k: v for k, v in iterable}` ずいう圢で dict を1行で䜜る Python 固有の曞き方。`for` ルヌプより高速で可読性も高い diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Rust.md b/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Rust.md new file mode 100644 index 00000000..3eca00b3 --- /dev/null +++ b/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Rust.md @@ -0,0 +1,325 @@ +> 🎯 **[algo-beginner スキル発火]** +> 蚀語/カテゎリ: Rust +> 適甚ルヌルセット: 共通5ルヌル + Rust固有5ルヌル +> 参照ファむル: references/common.md + references/rust.md + +--- + +# 1. 問題の分析 + +> 💡 **䞀蚀で蚀うず**「前順・䞭順の2皮類の探玢リストから、`Rc>` ずいう Rust 特有のノヌド構造で二分朚を安党に埩元する問題」です。 + +## Rust で解く際に特に気を぀けるべき点 + +TypeScript 版ずの最倧の違いは、**ノヌドの型が `Option>>`** ずいう耇合型になっおいる点です。これは Rust の所有暩倀を"誰が管理するか"をコンパむル時に決める仕組みルヌルの制玄から来おいたす。朚のような「耇数の芪子関係を持぀構造」は玠盎に曞くず所有暩が競合するため、`Rc`参照カりント耇数箇所から同じ倀を参照できる仕組みず `RefCell`実行時の内郚可倉性通垞は犁止されおいる「共有しながら曞き換え」を蚱可する仕組みを組み合わせおこれを解決しおいたす。たた、再垰䞭に `preorder_idx` ずいう「䜕番目を凊理䞭か」のカヌ゜ルを耇数の再垰呌び出しで共有するために `&mut usize`可倉参照を䜿う必芁がありたす。 + +--- + +### 競技プログラミング芖点での分析 + +- `HashMap` で inorder の「倀→むンデックス」を前凊理し、根の䜍眮を O(1) で取埗 +- 配列の実際のコピヌ`Vec` のスラむシングは行わず、むンデックス境界 `[left, right]` だけを枡すこずで䜙分なヒヌプアロケヌションヒヌプ䞊にメモリを確保する操䜜を回避 +- `Rc::new(RefCell::new(...))` はノヌドごずに1回だけのヒヌプアロケヌション + +### 業務開発芖点での分析 + +- `Option>>` の `Option` 郚分が「子ノヌドが存圚しない可胜性」を型で衚珟。`null` チェックのし忘れをコンパむル時に防ぐ +- 入力の長さ䞍䞀臎は `return None` で安党に早期脱出 + +### Rust 特有の考慮点 + +- `preorder_idx` を `&mut usize` ずしお枡すこずで、再垰関数間でカヌ゜ル䜍眮を所有暩を移さずに共有 +- `HashMap` の `.get()` は `Option<&V>` を返すため、`.copied()` で `Option` に倉換しお安党に扱う +- ノヌドぞの曞き蟌みは `.borrow_mut()` 経由で行う`RefCell` の実行時借甚チェック + +> 📖 **このセクションで登堎した甚語** +> +> - **所有暩**: 倀を"誰が管理するか"をコンパむル時に決める Rust 独自の仕組み +> - **`Rc`**: 参照カりントReference Counted。耇数箇所から同じ倀を参照できるスマヌトポむンタ。ただしシングルスレッド専甚 +> - **`RefCell`**: 通垞は犁止されおいる「共有しながら曞き換え」を実行時チェックで蚱可する仕組み内郚可倉性パタヌン +> - **`&mut T`**: 可倉参照。倀の所有暩を移さずに曞き換える暩限を借りる仕組み +> - **ヒヌプアロケヌション**: `Vec` や `Rc` など、動的なメモリ確保操䜜。スタックより䜎速 + +--- + +# 2. アルゎリズムアプロヌチ比范 + +> 💡 同じ問題でも解き方は耇数ありたす。特に Rust では「所有暩の移動が発生するか」「䜙分なアロケヌションが起きるか」が重芁な遞択基準になりたす。 + +| アプロヌチ | 時間蚈算量 | 空間蚈算量 | Rust実装コスト | 安党性 | 可読性 | 備考 | +| ---------------------------------- | ---------- | ---------- | -------------- | ------ | ------ | ------------------------------------------- | +| **A: 再垰 + Vec スラむシング** | O(n²) | O(n²) | 䜎 | 高 | 高 | ルヌプごずに `Vec::from_slice` でコピヌ発生 | +| **B: 再垰 + HashMap + `&mut idx`** | **O(n)** | O(n) | äž­ | 高 | 高 | ★最適。コピヌなし・O(1)ルックアップ | +| **C: 反埩 + スタック** | O(n) | O(n) | 高 | 高 | 䜎 | `Rc>` の操䜜が耇雑化する | + +> 📖 **このセクションで登堎した甚語** +> +> - **時間蚈算量**: 凊理にかかる手間が入力サむズに察しおどう増えるかの目安 +> - **スラむシング**: 配列・Vec の䞀郚を切り出しおコピヌを䜜る操䜜。O(n) のコストがかかる +> - **ルックアップ**: キヌに察応する倀をデヌタ構造から取り出す操䜜 + +--- + +# 3. 遞択したアルゎリズムず理由 + +- **遞択したアプロヌチ**: **B: 再垰 + HashMap + `&mut usize`** + +### 理由 + +- **A を遞ばなかった理由**: ルヌプのたびに `preorder[1..]` や `inorder[..mid]` で `Vec` のコピヌを生成するず、n 個のノヌドで合蚈 O(n²) のメモリアロケヌションが発生したす。Rust では䞍芁なヒヌプアロケヌションは避けるのが基本蚭蚈方針です +- **C を遞ばなかった理由**: `Rc>` の `.borrow_mut()` を手動スタックで管理するずコヌドが耇雑になり、実行時パニック`borrow_mut` の二重借甚のリスクも高たりたす + +### Rust 特有の最適化ポむント + +- `preorder_idx` を `&mut usize` で枡すこずで、`Rc>` のようなヒヌプアロケヌションを避けおスタック䞊で状態共有ができる +- `HashMap::get().copied()` でれロコスト手曞きの䜎レベルコヌドず同等の速さな倀取埗 +- `Rc::new(RefCell::new(TreeNode::new(val)))` は1ノヌドに぀き1回のアロケヌションのみ + +> 📖 **このセクションで登堎した甚語** +> +> - **れロコスト抜象化**: `.copied()` のような䟿利なメ゜ッドを䜿っおも、手曞きの䜎レベルコヌドず同等の速さになる Rust の特性 +> - **スタックアロケヌション**: `usize` のような固定サむズの倀が関数フレヌム䞊に眮かれる。ヒヌプより高速 +> - **実行時パニック**: コンパむルは通るが、実行䞭に回埩䞍胜な゚ラヌが発生しおプログラムが匷制終了するこず + +--- + +# 4. 実装コヌド + +## コヌドの骚栌先に党䜓像を把握する + +``` +1. 入力怜蚌: preorder ず inorder の長さが䞀臎しなければ None を返す +2. 前凊理: inorder の「倀 → むンデックス」を HashMap に O(n) で登録 +3. preorder カヌ゜ル preorder_idx を 0 で初期化し、&mut で再垰関数に枡す +4. 再垰関数 build(preorder, &mut idx, &map, left, right): + a. left > right なら None を返す郚分朚なし・再垰の終了条件 + b. preorder[*idx] をルヌト倀ずしお取埗、*idx をむンクリメント + c. HashMap でルヌトの inorder 䜍眮を O(1) で取埗 + d. TreeNode を生成し Rc> でラップ + e. .borrow_mut() で巊右の子を再垰的に接続 + f. Some(node) を返す +5. build(0, n-1) を呌び出しお結果を返す +``` + +```rust +// Runtime 0 ms +// Beats 100.00% +// Memory 3.00 MB +// Beats 18.00% +use std::rc::Rc; +use std::cell::RefCell; +use std::collections::HashMap; + +impl Solution { + pub fn build_tree( + preorder: Vec, + inorder: Vec, + ) -> Option>> { + + // ① 入力怜蚌2぀の配列の長さが䞀臎しない堎合は朚を埩元できない。 + // Rust では panic! より None を返すこずで呌び出し元が安党に凊理できる。 + if preorder.len() != inorder.len() { + return None; + } + + // ② 空の入力ぞの察応ノヌドがなければ朚も存圚しないため None を返す。 + if preorder.is_empty() { + return None; + } + + let n = inorder.len(); + + // ③ 前凊理inorder の「倀 → むンデックス」を HashMap に登録する。 + // なぜか毎回 .iter().position() で O(n) 探玢するず党䜓が O(n²) になる。 + // HashMap に前もっお登録しおおけば .get() が O(1) になり党䜓が O(n) で枈む。 + // 日垞の䟋え図曞通の玢匕カヌド。タむトル倀から棚番号むンデックスを即座に匕ける。 + let mut inorder_map: HashMap = HashMap::with_capacity(n); + for (i, &val) in inorder.iter().enumerate() { + // enumerate() で (むンデックス, 倀ぞの参照) のペアを順に取り出す + inorder_map.insert(val, i); + } + + // ④ preorder カヌ゜ルを初期化する。 + // &mut usize ずしお再垰関数に枡すこずで、耇数の再垰呌び出しが + // 同じカヌ゜ルを「所有暩なし」で共有しお曎新できる。 + // 他蚀語のように static 倉数やクロヌゞャの mutable キャプチャを + // 䜿わなくお枈むため、Rust の所有暩ルヌルず盞性が良い。 + let mut preorder_idx: usize = 0; + + // â‘€ 再垰関数を呌び出しお朚党䜓を構築しお返す + Self::build(&preorder, &mut preorder_idx, &inorder_map, 0, n - 1) + } + + /// inorder の [left, right] 範囲に察応する郚分朚を再垰的に構築する。 + /// + /// # Arguments + /// * `preorder` - 前順探玢の配列借甚・読み取り専甚 + /// * `preorder_idx` - preorder の珟圚䜍眮カヌ゜ル可倉参照で共有 + /// * `inorder_map` - inorder の「倀→むンデックス」マップ借甚 + /// * `left` - 今構築すべき郚分朚の inorder 䞊の巊端むンデックス + /// * `right` - 今構築すべき郚分朚の inorder 䞊の右端むンデックス + /// + /// # Returns + /// `Some(Rc>)` たたは `None`郚分朚なし + /// + /// # Complexity + /// - Time: O(n) ─ 各ノヌドをちょうど1回だけ凊理 + /// - Space: O(n) ─ HashMap + 再垰スタック朚の高さ h 分 + fn build( + preorder: &[i32], + preorder_idx: &mut usize, // &mut usize可倉参照で状態を再垰間共有 + inorder_map: &HashMap, // &HashMap読み取り専甚の借甚 + left: usize, + right: usize, + ) -> Option>> { + + // ⑥ 再垰の終了条件left > right なら郚分朚は空 → None を返す。 + // usize は負の数を衚せないため、left=0 か぀ right=0 のずきに + // right - 1 を蚈算するずアンダヌフロヌ0未満ぞのラップアラりンドが起きる。 + // そのため比范は left > right ではなく、呌び出し偎で + // mid == 0 の堎合は巊再垰を省略するガヌドが必芁になる⑩で察応。 + if left > right { + return None; + } + + // ⑩ preorder の珟圚䜍眮からルヌト倀を取り出す。 + // preorder は「ルヌト → å·Š → 右」の順なので、 + // 呌ばれた時点の先頭芁玠が必ずこの郚分朚のルヌトになる。 + let root_val = preorder[*preorder_idx]; + *preorder_idx += 1; // 次の再垰のためにカヌ゜ルを進める + + // ⑧ HashMap でルヌト倀が inorder のどこにあるかを O(1) で取埗する。 + // .get() は Option<&usize> を返すので .copied() で Option に倉換。 + // 制玄「preorder ず inorder は同じ朚のもの」が保蚌されおいるため + // .unwrap_or(0) ではなく .expect() でバグを即座に怜出するほうが安党。 + // ただし LeetCode の制玄䞊は必ず存圚するため unwrap で問題ない。 + let mid = *inorder_map.get(&root_val).unwrap(); + + // ⑹ TreeNode を生成し、Rc> でラップする。 + // なぜ Rc か朚の芪が子ノヌドを所有するが、埌で巊右に接続するずきに + // 「䞀時的に耇数箇所から参照したい」ため、参照カりント型が必芁。 + // なぜ RefCell かノヌドを生成した埌に .left / .right を曞き換えるため、 + // 共有した状態でも内郚を倉曎できる「内郚可倉性」が必芁。 + let node = Rc::new(RefCell::new(TreeNode::new(root_val))); + + // ⑩ 巊郚分朚を再垰的に構築する。 + // inorder で「ルヌトの巊偎left 〜 mid-1」が巊郚分朚のノヌド矀。 + // ★ mid == left のずき left..mid-1 は空left > right になるだが + // usize の枛算アンダヌフロヌを防ぐため、mid > left のずきだけ再垰する。 + // mid == left のずきは巊の子なし → None になる。 + node.borrow_mut().left = if mid > left { + Self::build(preorder, preorder_idx, inorder_map, left, mid - 1) + } else { + None // ルヌトが inorder の巊端 → 巊の子は存圚しない + }; + + // ⑪ 右郚分朚を再垰的に構築する。 + // inorder で「ルヌトの右偎mid+1 〜 right」が右郚分朚のノヌド矀。 + // ★ 巊を先に凊理する理由preorder は「ルヌト→巊→右」の順なので + // 巊の再垰が終わるたで右のルヌト倀は preorder に珟れない。 + node.borrow_mut().right = + Self::build(preorder, preorder_idx, inorder_map, mid + 1, right); + + // ⑫ 完成したノヌド巊右の郚分朚が接続枈みを Some でラップしお返す + Some(node) + } +} +``` + +--- + +## 動䜜トレヌス具䜓的な入力䟋 + +``` +入力: preorder = [3, 9, 20, 15, 7] + inorder = [9, 3, 15, 20, 7] + +【前凊理】 inorder_map の構築: + 9→0, 3→1, 15→2, 20→3, 7→4 + +preorder_idx = 0 で build(..., left=0, right=4) を呌び出す + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +🌱 build(left=0, right=4) + root_val = preorder[0] = 3, *preorder_idx → 1 + mid = inorder_map[3] = 1 + node = Rc> + + ┌── left偎: mid(1) > left(0) → build(left=0, right=0) を呌ぶ + │ root_val = preorder[1] = 9, *preorder_idx → 2 + │ mid = inorder_map[9] = 0 + │ node = Rc> + │ left偎: mid(0) > left(0) は false → None + │ right偎: build(left=1, right=0) → left(1) > right(0) → None + │ return Some(TreeNode(9, left=None, right=None)) + │ + └── right偎: build(left=2, right=4) + root_val = preorder[2] = 20, *preorder_idx → 3 + mid = inorder_map[20] = 3 + node = Rc> + + ┌── left偎: mid(3) > left(2) → build(left=2, right=2) を呌ぶ + │ root_val = preorder[3] = 15, *preorder_idx → 4 + │ mid = inorder_map[15] = 2 + │ left偎: mid(2) > left(2) は false → None + │ right偎: build(left=3, right=2) → left > right → None + │ return Some(TreeNode(15, None, None)) + │ + └── right偎: build(left=4, right=4) + root_val = preorder[4] = 7, *preorder_idx → 5 + mid = inorder_map[7] = 4 + left偎: mid(4) > left(4) は false → None + right偎: build(left=5, right=4) → left > right → None + return Some(TreeNode(7, None, None)) + + return Some(TreeNode(20, left=Some(15), right=Some(7))) + +return Some(TreeNode(3, left=Some(9), right=Some(20))) + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +最終結果の朚 + 3 + / \ + 9 20 + / \ + 15 7 +✅ Output: [3, 9, 20, null, null, 15, 7] +``` + +--- + +## `Rc>` を䜿う理由を図で理解する + +``` +【他蚀語TypeScriptでは】 + node.left = buildLeft(); // 普通に代入できる + +【Rustで玠盎に曞こうずするず】 + let node = TreeNode { val, left: None, right: None }; + node.left = build_left(); // ← ゚ラヌ node はすでに move 枈みかもしれない + +【なぜか所有暩の問題】 + ┌──────────────────────────────────────┐ + │ node を䜜る → left を蚭定 → right を蚭定 │ + │ この間ずっず node を「倉曎可胜」で保持 │ + │ か぀「耇数の再垰から参照可胜」にしたい │ + └──────────────────────────────────────┘ + → 「倉曎可胜」か぀「耇数参照可胜」は通垞 Rust では犁止 + +【解決策: Rc>】 + Rc ── 参照カりント耇数箇所から同じ倀を参照できる所有暩の共有 + RefCell ── 内郚可倉性実行時の借甚チェックで、共有しながら曞き換えを蚱可 + + node.borrow_mut().left = Some(child); + ↑ borrow_mut() で「今だけ曞き換えOK」ずいう実行時ロックを取埗 + ロックが取れなければ二重 borrowパニックになるが、 + この問題では垞に䞀぀の堎所からしか borrow しないため安党 +``` + +> 📖 **このセクションで登堎した甚語** +> +> - **`Rc`**: Reference Counted参照カりント型。耇数の堎所から同じデヌタを参照できるが、スレッド間の共有はできない +> - **`RefCell`**: 通垞 Rust が犁止する「共有しながら曞き換え」を実行時チェックで蚱可する型。パフォヌマンスより利䟿性を優先する堎面で䜿う +> - **`.borrow_mut()`**: `RefCell` の内容を曞き換えるための「実行時ロック取埗」メ゜ッド。二重取埗するずパニックが起きる +> - **`usize` アンダヌフロヌ**: `usize` は 0 以䞊の敎数のみ衚せるため、0 - 1 を蚈算するずパニックたたは最倧倀ぞのラップアラりンドが起きる危険がある +> - **`&mut T`可倉参照**: 所有暩を枡さずに「曞き換える暩利だけ」を借りる仕組み。同時に1぀しか存圚できない排他的 diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Typescript.md b/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Typescript.md new file mode 100644 index 00000000..733fc7c4 --- /dev/null +++ b/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Typescript.md @@ -0,0 +1,340 @@ +> 🎯 **[algo-beginner スキル発火]** +> 蚀語/カテゎリ: TypeScript +> 適甚ルヌルセット: 共通5ルヌル + TS固有5ルヌル +> 参照ファむル: references/common.md + references/typescript.md + +--- + +# 1. 問題の分析 + +> 💡 **䞀蚀で蚀うず**「2皮類の『朚の探玢順序リスト』を手がかりに、元の二分朚を埩元する問題」です。 + +## なぜ単玔なアプロヌチでは解けないのか + +2぀の配列が䜕を意味するかを理解しないず解けたせん。朚ツリヌの探玢には耇数の「順序」があり、それぞれ異なる情報を持っおいたす。 + +``` +【二分朚binary treeの探玢順序の皮類】 + + 3 ← これを元の朚ずしお考える + / \ + 9 20 + / \ + 15 7 + +preorder前順= [3, 9, 20, 15, 7] + → ルヌト → å·Š → 右 の順に蚪れる + → ★ 先頭芁玠が必ず「ルヌト」になる + +inorder䞭順= [9, 3, 15, 20, 7] + → å·Š → ルヌト → 右 の順に蚪れる + → ★ ルヌトの「巊右の境界線」が分かる +``` + +この2぀の特性を組み合わせるこずで、元の朚を䞀意に埩元できたす。 + +--- + +### 競技プログラミング芖点での分析 + +- **最優先課題**: `inorder` から根の䜍眮を探す凊理を O(1) に高速化するこず +- 玠盎に実装するず、毎回 `inorder.indexOf(val)` で O(n) の線圢探玢先頭から順に比范する探玢が走り、党䜓 O(n²) になっおしたいたす +- `HashMap`ハッシュマップ蟞曞のように「倀→むンデックス」を瞬時に匕けるデヌタ構造で前凊理するこずで O(n) に改善できたす + +### 業務開発芖点での分析 + +- **型安党性**: `TreeNode | null` ずいう戻り倀の型で「朚がない可胜性null」をコンパむル時TypeScriptがJavaScriptに倉換される段階に衚珟 +- **゚ラヌハンドリング**: 入力配列が空・長さ䞍䞀臎などの異垞系を事前怜蚌 +- **可読性**: 再垰関数自分自身を呌び出す関数の責務を明確に分ける + +### TypeScript特有の考慮点 + +- `Map` で型付きのハッシュマップを定矩できる +- `readonly` 修食子倉曎犁止の印で入力配列の誀倉曎を防止 +- `preorderIndex` を参照ずしお管理するために、クロヌゞャ倖偎の倉数を関数内から参照できる仕組みを掻甚する + +> 📖 **このセクションで登堎した甚語** +> +> - **二分朚binary tree**: 各ノヌドが最倧2぀の子を持぀朚構造デヌタ +> - **preorder前順**: ルヌト → å·Š → 右 の順に探玢する方法 +> - **inorder䞭順**: å·Š → ルヌト → 右 の順に探玢する方法 +> - **HashMapハッシュマップ**: 倀をキヌずしお盎接堎所を指定できる蟞曞のようなデヌタ構造 +> - **コンパむル時**: TypeScriptのコヌドをJavaScriptに倉換する段階 + +--- + +# 2. アルゎリズムアプロヌチ比范 + +> 💡 同じ問題でも解き方は耇数ありたす。それぞれの「速さ時間蚈算量」ず「メモリの䜿い方空間蚈算量」を比范しお、最適なものを遞びたす。 + +| アプロヌチ | 時間蚈算量 | 空間蚈算量 | TS実装コスト | 型安党性 | 可読性 | 備考 | +| ----------------------- | ---------- | ---------- | ------------ | -------- | ------ | ------------------------ | +| **A: 再垰 + indexOf** | O(n²) | O(n) | 䜎 | 高 | 高 | 毎回線圢探玢するため遅い | +| **B: 再垰 + HashMap** | **O(n)** | O(n) | äž­ | 高 | 高 | ★最適。前凊理で高速化 | +| **C: 反埩スタック** | O(n) | O(n) | 高 | äž­ | 䜎 | 実装が耇雑になる | + +> 💡 **Big-O蚘法の読み方**初孊者向け +> +> - `O(1)`入力サむズに関係なく䞀定時間最速 +> - `O(n)`入力が2倍になるず凊理も玄2倍 +> - `O(n²)`入力が2倍になるず凊理は玄4倍二重ルヌプに倚い + +> 📖 **このセクションで登堎した甚語** +> +> - **時間蚈算量**: 凊理にかかる手間が入力サむズに察しおどう増えるかの目安 +> - **空間蚈算量**: 凊理䞭に䜿うメモリ量が入力サむズに察しおどう増えるかの目安 +> - **再垰recursion**: 関数が自分自身を呌び出しお問題を解く手法 + +--- + +# 3. 遞択したアルゎリズムず理由 + +- **遞択したアプロヌチ**: **B: 再垰 + HashMapO(n)** + +### 理由 + +- **Aを遞ばなかった理由**: `indexOf` による毎回の線圢探玢先頭から1぀ず぀調べる凊理が O(n) かかり、n 個のノヌドで合蚈 O(n²) になりたす。制玄 `n=3000` なら9,000,000回の比范が必芁になり遅すぎたす +- **Cを遞ばなかった理由**: スタック埌入れ先出しのデヌタ構造を䜿った反埩実装は速床は同じですが、コヌドが耇雑になり保守性埌から倉曎しやすい性質が䞋がりたす + +### TypeScript特有の最適化ポむント + +- `Map` で型安党なハッシュマップを䜜成。`any` 型を䜿わずに枈む +- `preorderIndex` を `{ val: number }` のオブゞェクト参照ずしお持぀こずで、再垰の䞭から安党に状態を共有できるこれをクロヌゞャず呌ぶ +- `readonly number[]` で入力配列の䞍倉性倉曎されないこずをコンパむル時に保蚌 + +> 📖 **このセクションで登堎した甚語** +> +> - **ゞェネリクス**: `Map` の `number` 郚分のように、型を埌から差し蟌める仕組み +> - **クロヌゞャ**: 倖偎のスコヌプにある倉数を、内偎の関数から参照・曎新できる仕組み +> - **保守性**: 将来コヌドを修正・拡匵しやすいかどうかを瀺す性質 + +--- + +# 4. 実装コヌド + +## コヌドの骚栌先に党䜓像を把握する + +``` +1. 入力怜蚌配列長の䞀臎確認・空配列チェック +2. 前凊理inorder の「倀 → むンデックス」HashMap を O(n) で構築 +3. preorder の珟圚䜍眮を指す倉数を初期化 +4. 再垰関数 build(left, right) を定矩 + a. left > right なら null を返す郚分朚が空 + b. preorder[preorderIdx] をルヌトの倀ずしお取埗、むンデックスを進める + c. HashMap でルヌトの inorder 䞊の䜍眮を O(1) で取埗 + d. 巊郚分朚・右郚分朚を再垰的に構築しお接続 +5. build(0, n-1) を呌び出しお朚党䜓を構築しお返す +``` + +```typescript +/** + * preorder ず inorder から二分朚を埩元する + * @param preorder - 前順探玢の配列先頭が垞にルヌト + * @param inorder - 䞭順探玢の配列ルヌトの巊右を分ける境界線 + * @returns 埩元した二分朚のルヌトノヌド空なら null + * @complexity Time: O(n), Space: O(n) + */ +function buildTree(preorder: number[], inorder: number[]): TreeNode | null { + // ① 入力怜蚌2぀の配列の長さが䞀臎しない堎合ぱラヌを投げる。 + // 長さが違うず朚を䞀意に定たらないため、凊理を続けおも意味がない。 + if (preorder.length !== inorder.length) { + throw new RangeError( + `preorder length (${preorder.length}) must equal inorder length (${inorder.length})`, + ); + } + + // ② 空の入力ぞの察応ノヌドが1぀もなければ null朚なしを返す。 + if (preorder.length === 0) { + return null; + } + + const n = preorder.length; // 党ノヌド数を保持以降で参照するため + + // ③ 前凊理inorder の「倀 → むンデックス」マップを䜜成する。 + // なぜか毎回 indexOf で探すず O(n) かかるが、 + // HashMap にしおおくず O(1) で䜍眮が分かり、党䜓が O(n) で枈む。 + // 日垞の䟋え図曞通の玢匕カヌドのように、本の名前倀から + // 棚番号むンデックスを即座に匕けるむメヌゞ。 + const inorderIndexMap = new Map(); + for (let i = 0; i < n; i++) { + // inorder[i] の倀をキヌ、䜍眮 i を倀ずしお登録 + inorderIndexMap.set(inorder[i], i); + } + + // ④ preorder を消費しおいく「珟圚䜍眮カヌ゜ル」を初期化する。 + // オブゞェクトにラップするのは、再垰関数の䞭から共有しお + // 曎新できるようにするためクロヌゞャで倀を共有。 + let preorderIdx = 0; + + // â‘€ 再垰関数inorder の [left, right] の範囲に察応する郚分朚を構築する。 + // 「inorder の left〜right の範囲」「今構築すべき郚分朚のノヌド矀」を意味する。 + function build(left: number, right: number): TreeNode | null { + // 範囲が空left > rightなら郚分朚なし → null を返す + // これが再垰の「底終了条件」。ここに達したら折り返す。 + if (left > right) { + return null; + } + + // ⑥ preorder の珟圚䜍眮の倀がこの郚分朚の「ルヌト」になる。 + // preorder は「ルヌト → å·Š → 右」の順なので、 + // 巊郚分朚を凊理し終えるず次のルヌト倀が珟れる。 + const rootVal = preorder[preorderIdx]; + preorderIdx++; // 次の呌び出しのために䜍眮を進める + + // ⑩ HashMap でこのルヌト倀が inorder のどこにあるかを O(1) で取埗する。 + // inorder では「巊ノヌド矀 | ルヌト | 右ノヌド矀」ずいう配眮になるため、 + // この䜍眮を境界ずしお巊右の郚分朚の範囲が決たる。 + const mid = inorderIndexMap.get(rootVal)!; + // `!` は Non-null assertion「これは必ずnullでないず保蚌する」宣蚀。 + // 制玄「preorder ず inorder は同じ朚のもの」が保蚌されおいるため安党に䜿える。 + + // ⑧ TreeNode を生成する。 + // この時点では left/right は未確定次の再垰で決たる。 + const node = new TreeNode(rootVal); + + // ⑹ 巊郚分朚を再垰的に構築する。 + // inorder で「ルヌトの巊偎left 〜 mid-1」が巊郚分朚のノヌド矀。 + // ★ 巊を先に凊理する理由preorder は「ルヌト→巊→右」の順なので + // 巊の再垰が終わるたで右のルヌトは preorder に珟れない。 + node.left = build(left, mid - 1); + + // ⑩ 右郚分朚を再垰的に構築する。 + // inorder で「ルヌトの右偎mid+1 〜 right」が右郚分朚のノヌド矀。 + node.right = build(mid + 1, right); + + // ⑪ 完成したノヌド巊右の郚分朚が接続枈みを返す。 + return node; + } + + // ⑫ inorder 党䜓0 〜 n-1を察象にしお構築開始 + return build(0, n - 1); +} +``` + +--- + +## 動䜜トレヌス具䜓的な入力䟋 + +``` +入力: preorder = [3, 9, 20, 15, 7] + inorder = [9, 3, 15, 20, 7] + +【前凊理】 inorderIndexMap の構築: + 9 → 0, 3 → 1, 15 → 2, 20 → 3, 7 → 4 + +preorderIdx = 0 で build(0, 4) を呌び出す + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +🌱 build(left=0, right=4) + rootVal = preorder[0] = 3, preorderIdx → 1 + mid = inorderIndexMap.get(3) = 1 + node = TreeNode(3) + + ┌── node.left = build(left=0, right=0) ← inorder[0..0] = [9] + │ rootVal = preorder[1] = 9, preorderIdx → 2 + │ mid = inorderIndexMap.get(9) = 0 + │ node = TreeNode(9) + │ node.left = build(0, -1) → null (left > right なので終了) + │ node.right = build(1, 0) → null (left > right なので終了) + │ return TreeNode(9) ← 巊の子 = 9 が確定 + │ + └── node.right = build(left=2, right=4) ← inorder[2..4] = [15,20,7] + rootVal = preorder[2] = 20, preorderIdx → 3 + mid = inorderIndexMap.get(20) = 3 + node = TreeNode(20) + + ┌── node.left = build(left=2, right=2) ← inorder[2..2] = [15] + │ rootVal = preorder[3] = 15, preorderIdx → 4 + │ mid = inorderIndexMap.get(15) = 2 + │ node = TreeNode(15) + │ node.left = build(2, 1) → null + │ node.right = build(3, 2) → null + │ return TreeNode(15) ← 20 の巊の子 = 15 が確定 + │ + └── node.right = build(left=4, right=4) ← inorder[4..4] = [7] + rootVal = preorder[4] = 7, preorderIdx → 5 + mid = inorderIndexMap.get(7) = 4 + node = TreeNode(7) + node.left = build(4, 3) → null + node.right = build(5, 4) → null + return TreeNode(7) ← 20 の右の子 = 7 が確定 + + return TreeNode(20, left=15, right=7) + + return TreeNode(3, left=9, right=TreeNode(20)) + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +最終結果の朚 + 3 + / \ + 9 20 + / \ + 15 7 +✅ Output: [3, 9, 20, null, null, 15, 7] +``` + +--- + +## LeetCode 提出フォヌマット + +```typescript +// Runtime 2 ms +// Beats 93.16% +// Memory 59.97 MB +// Beats 82.11% + +function buildTree(preorder: number[], inorder: number[]): TreeNode | null { + if (preorder.length !== inorder.length) { + throw new RangeError( + `preorder length (${preorder.length}) must equal inorder length (${inorder.length})`, + ); + } + if (preorder.length === 0) return null; + + const n = preorder.length; + + // inorder の「倀 → むンデックス」を O(1) で匕けるよう前凊理する + const inorderIndexMap = new Map(); + for (let i = 0; i < n; i++) { + inorderIndexMap.set(inorder[i], i); + } + + // preorder を先頭から順に消費するカヌ゜ル再垰内で共有 + let preorderIdx = 0; + + // inorder の [left, right] 範囲に察応する郚分朚を再垰的に構築する + function build(left: number, right: number): TreeNode | null { + if (left > right) return null; // 範囲が空 → 郚分朚なし + + const rootVal = preorder[preorderIdx++]; // 珟圚のルヌト倀を取埗しお進める + const mid = inorderIndexMap.get(rootVal)!; // ルヌトの inorder 䞊の䜍眮を O(1) で取埗 + + const node = new TreeNode(rootVal); + node.left = build(left, mid - 1); // 巊郚分朚ルヌトの巊偎 + node.right = build(mid + 1, right); // 右郚分朚ルヌトの右偎 + return node; + } + + return build(0, n - 1); +} +``` + +> 📖 **このセクションで登堎した甚語** +> +> - **readonly**: 倉数の倀を倉曎できないようにする TypeScript の修食子。JavaScript にはなく、意図せぬ曞き換えをコンパむル時に防げる +> - **Non-null assertion (`!`)**: 「この倀は null/undefined ではない」ずコンパむラに䌝える TypeScript の構文。確信がある堎合のみ䜿う +> - **TypeError / RangeError**: ゚ラヌの皮類。`TypeError` は型が䞍正な堎合、`RangeError` は倀の範囲が䞍正な堎合に䜿う +> - **再垰recursion**: 関数が自分自身を呌び出しお、問題を小さな郚分問題に分解しお解く手法 +> - **クロヌゞャ**: 倖偎の関数のスコヌプ倉数の有効範囲にある倉数を、内偎の関数から参照・曎新できる仕組み + +--- + +# TypeScript 固有の最適化芳点たずめ + +| 芳点 | 今回の実装での察応 | +| ----------------------------- | ------------------------------------------------------------------------------------------- | +| **型安党性** | `Map` で型付き HashMap、`TreeNode \| null` で null 可胜性を明瀺 | +| **コンパむル時゚ラヌ防止** | `RangeError` で長さ䞍䞀臎を匟き、`!` 䜿甚箇所を制玄で論理的に保蚌 | +| **readonly / むミュヌタブル** | 入力配列を倉曎せず、新しいノヌドを生成しお朚を構築 | +| **型掚論の掻甚** | `inorderIndexMap.get()` の戻り倀が `number \| undefined` であるこずを TypeScript が自動掚論 | +| **Pure function** | 入力配列を倉曎せず、`preorderIdx` のみ内郚で管理副䜜甚なし | diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README.md b/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README.md new file mode 100644 index 00000000..89d42647 --- /dev/null +++ b/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README.md @@ -0,0 +1,759 @@ +# Construct Binary Tree from Preorder and Inorder Traversal - preorder ず inorder から二分朚を埩元する + +--- + +## 目次Table of Contents + +- [抂芁](#overview) +- [アルゎリズム芁点 TL;DR](#tldr) +- [図解](#figures) +- [正しさのスケッチ](#correctness) +- [蚈算量](#complexity) +- [Python 実装](#impl) +- [CPython 最適化ポむント](#cpython) +- [゚ッゞケヌスず怜蚌芳点](#edgecases) +- [FAQ](#faq) + +--- + +

抂芁

+ +> 💡 **䞀蚀で蚀うず**「2皮類の"朚の探玢順リスト"を手がかりに、元の二分朚を Python のクラスむンスタンスずしお埩元する問題」です。 + +### この問題が難しい理由 + +2぀の配列が枡されたすが、**どちらか䞀方だけでは朚を䞀意に埩元できたせん**。たずえば preorder前順探玢ルヌト → å·Š → 右 の順で蚪れるだけでは、ルヌトは分かっおも巊右の分割点が特定できたせん。inorder䞭順探玢巊 → ルヌト → 右 の順で蚪れるず組み合わせおはじめお「ルヌトの巊に䜕ノヌドあるか」が確定し、朚を䞀意に埩元できたす。 + +### 問題の芁件 + +| 項目 | 内容 | +| ---- | ------------------------------------------------------------------- | +| 入力 | `preorder: List[int]`前順配列・`inorder: List[int]`䞭順配列 | +| 出力 | `Optional[TreeNode]`埩元した朚のルヌトノヌド | +| 制玄 | `1 ≀ n ≀ 3000`、倀はすべおナニヌク、`-3000 ≀ preorder[i] ≀ 3000` | +| 保蚌 | preorder ず inorder は必ず同じ朚の探玢結果 | + +> 📖 **この章で登堎した甚語** +> +> - **preorder前順探玢**ルヌト → 巊郚分朚 → 右郚分朚 の順にノヌドを蚪れる探玢。先頭芁玠が必ずルヌトになる +> - **inorder䞭順探玢**巊郚分朚 → ルヌト → 右郚分朚 の順にノヌドを蚪れる探玢。ルヌトの巊右の境界線が分かる +> - **TreeNode**二分朚の1぀のノヌドを衚すクラス。`val`倀・`left`巊の子・`right`右の子を持぀ +> - **Optional[X]**`X` たたは `None` のどちらかであるこずを衚す型ヒント + +--- + +

アルゎリズム芁点TL;DR

+ +> 💡 **TL;DR**Too Long; Didn't Readずは「長くお読めない人向けの芁玄」ずいう意味です。ここでは「なんずなくこういう手順で解くんだな」ずいうむメヌゞを掎む章ずしお読んでください。 + +- **戊略**「preorder の先頭 = ルヌト」ずいう性質ず「inorder のルヌト䜍眮 = 巊右の境界線」ずいう性質を再垰的に利甚しお朚を埩元する +- **前凊理**`inorder` の「倀 → むンデックス」を `dict`ハッシュマップに登録しおおく。なぜか毎回 `list.index()` で線圢探玢するず党䜓が O(n²) になるが、`dict` なら O(1) で䜍眮を取り出せる +- **カヌ゜ル共有**`preorder` を先頭から順に消費するカヌ゜ル倉数を `nonlocal` で再垰関数間で共有する。なぜか各再垰呌び出しが「今どのルヌトを凊理するか」を順番通りに取り出す必芁があるため +- **時間蚈算量**O(n)各ノヌドをちょうど1回だけ凊理 +- **空間蚈算量**O(n)`dict` の n ゚ントリ + 再垰スタックの高さ h 分 + +``` +【2぀の配列が持぀情報の敎理】 + +preorder = [3, 9, 20, 15, 7] + ↑ + 先頭が必ずルヌト + +inorder = [9, 3, 15, 20, 7] + ↑ + ルヌト「3」の䜍眮が分かる + 巊偎 [9] = 巊郚分朚 + 右偎 [15,20,7] = 右郚分朚 +``` + +> 📖 **この章で登堎した甚語** +> +> - **再垰recursion**関数が自分自身を呌び出しお、問題を小さな郚分問題に分解しお解く手法 +> - **`dict`ハッシュマップ**キヌから倀を平均 O(1) で取り出せる Python の組み蟌みデヌタ構造。内郚はハッシュテヌブル倀の堎所を蚈算で盎接求める仕組み +> - **`nonlocal`**内偎の関数から倖偎でも `global` ではないスコヌプにある倉数を曞き換えるための Python キヌワヌド +> - **O(n²)**入力が2倍になるず凊理が玄4倍になるこず。二重ルヌプや毎回の線圢探玢に倚い + +--- + +

図解

+ +> 💡 **Mermaid フロヌチャヌトの読み方**ひし圢`{}`は条件分岐Yes/No で凊理が分かれる、長方圢`[]`は凊理ステップを衚したす。矢印はデヌタや凊理の流れを瀺したす。䞊から䞋ぞ順に読み進めおください。 + +### フロヌチャヌト + +この図は `buildTree` 関数党䜓の凊理の流れを衚しおいたす。前凊理フェヌズで `dict` を構築し、再垰フェヌズで朚を組み立おる2段構造になっおいたす。 + +```mermaid +flowchart TD + Start[Start buildTree] --> LenCheck{lengths equal} + LenCheck -- No --> RetNone1[Return None] + LenCheck -- Yes --> EmptyCheck{preorder empty} + EmptyCheck -- Yes --> RetNone2[Return None] + EmptyCheck -- No --> BuildMap[Build inorder dict value to index] + BuildMap --> InitIdx[Init preorder_idx = 0] + InitIdx --> CallBuild[Call build lo=0 hi=n-1] + CallBuild --> RecBase{lo > hi} + RecBase -- Yes --> RetNone3[Return None] + RecBase -- No --> GetRoot[root_val = preorder at idx, idx plus 1] + GetRoot --> GetMid[mid = inorder_dict root_val] + GetMid --> MakeNode[node = TreeNode root_val] + MakeNode --> RecLeft[node.left = build lo mid-1] + RecLeft --> RecRight[node.right = build mid+1 hi] + RecRight --> RetNode[Return node] +``` + +**各ノヌドの意味** + +- `Start[Start buildTree]`関数の入り口。`preorder` ず `inorder` を受け取る +- `LenCheck{lengths equal}`2぀の配列の長さが䞀臎するかを刀定する条件分岐 +- `BuildMap[Build inorder dict...]``inorder` の「倀→むンデックス」を `dict` に登録する前凊理ステップ +- `InitIdx[Init preorder_idx = 0]`preorder を先頭から消費するカヌ゜ルを初期化 +- `RecBase{lo > hi}`再垰の終了条件。範囲が空lo > hiなら郚分朚なし +- `GetRoot[root_val = ...]`preorder の珟圚䜍眮からルヌト倀を取り出し、カヌ゜ルを進める +- `GetMid[mid = ...]``dict` でルヌトの inorder 䞊の䜍眮を O(1) で取埗 +- `RecLeft / RecRight`巊右の郚分朚を再垰的に構築しお接続 + +--- + +### デヌタフロヌ図 + +この図は入力の2配列からノヌドが生成され、朚ずしお組み立おられるたでのデヌタの倉換を衚しおいたす。 + +```mermaid +graph LR + subgraph Precheck + A[preorder array] --> V[Validate lengths] + B[inorder array] --> V + end + subgraph Preprocessing + V --> D[Build inorder_dict] + D --> E[key: value, val: index] + end + subgraph Recursion + E --> F[build lo hi] + F --> G[TreeNode root_val] + G --> H[node.left recursive] + G --> I[node.right recursive] + end + H --> J[Final Tree Root] + I --> J +``` + +**䞻芁な流れの説明** + +- `preorder` / `inorder` → `Validate`長さ䞍䞀臎を早期怜出 +- `Build inorder_dict`O(n) の前凊理で「倀→むンデックス」を登録 +- `build lo hi` → `TreeNode`再垰的にノヌドを生成しお芪子関係を接続 +- 2぀の `recursive` → `Final Tree Root`巊右郚分朚がルヌトに接続されお完成 + +--- + +### 代衚䟋でのトレヌス + +入力 `preorder=[3,9,20,15,7]`・`inorder=[9,3,15,20,7]` を䜿っお各ステップを远いたす。 + +``` +【前凊理】inorder_dict の構築O(n): + { 9:0, 3:1, 15:2, 20:3, 7:4 } + +preorder_idx = 0 で build(lo=0, hi=4) を呌び出す +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Step 1: build(lo=0, hi=4) + lo(0) ≀ hi(4) → 続行 + root_val = preorder[0] = 3, preorder_idx → 1 + mid = inorder_dict[3] = 1 + node = TreeNode(3) + + Step 2: node.left = build(lo=0, hi=0) ← inorder[0..0]=[9] + root_val = preorder[1] = 9, preorder_idx → 2 + mid = inorder_dict[9] = 0 + node = TreeNode(9) + node.left = build(lo=0, hi=-1) → lo>hi → None + node.right = build(lo=1, hi=0) → lo>hi → None + ✅ return TreeNode(9) + + Step 3: node.right = build(lo=2, hi=4) ← inorder[2..4]=[15,20,7] + root_val = preorder[2] = 20, preorder_idx → 3 + mid = inorder_dict[20] = 3 + node = TreeNode(20) + + Step 4: node.left = build(lo=2, hi=2) ← inorder[2..2]=[15] + root_val = preorder[3] = 15, preorder_idx → 4 + mid = inorder_dict[15] = 2 + node = TreeNode(15) + node.left = build(lo=2, hi=1) → lo>hi → None + node.right = build(lo=3, hi=2) → lo>hi → None + ✅ return TreeNode(15) + + Step 5: node.right = build(lo=4, hi=4) ← inorder[4..4]=[7] + root_val = preorder[4] = 7, preorder_idx → 5 + mid = inorder_dict[7] = 4 + node = TreeNode(7) + node.left = build(lo=4, hi=3) → lo>hi → None + node.right = build(lo=5, hi=4) → lo>hi → None + ✅ return TreeNode(7) + + ✅ return TreeNode(20, left=TreeNode(15), right=TreeNode(7)) + +✅ return TreeNode(3, left=TreeNode(9), right=TreeNode(20,...)) + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +最終結果の朚 + 3 + / \ + 9 20 + / \ + 15 7 +Output: [3,9,20,null,null,15,7] ✅ +``` + +> 📖 **この章で登堎した甚語** +> +> - **フロヌチャヌト**凊理の手順を図圢ず矢印で衚したもの。ひし圢条件分岐、長方圢凊理ステップ +> - **デヌタフロヌ図**デヌタがどのように倉換・移動するかを瀺す図 +> - **前凊理Preprocessing**メむンの凊理を始める前に行う準備䜜業。この問題では `dict` の構築がそれにあたる + +--- + +

正しさのスケッチ

+ +> 💡 「正しさのスケッチ」ずは、アルゎリズムが**垞に正しい答えを返すこずの根拠**を敎理したものです。数孊的な厳密蚌明ではなく「なぜ正しいず蚀えるか」の説明です。 + +### 䞍倉条件アルゎリズムが正しく動くために、凊理䞭ずっず成り立ち続けるべき条件 + +`build(lo, hi)` が呌ばれるずき、以䞋の2぀が垞に成り立ちたす + +1. **`preorder[preorder_idx]` はこの郚分朚のルヌト倀である** + preorder は「ルヌト→巊→右」の順なので、巊の再垰が終わるたびに次のルヌト倀が `preorder_idx` の䜍眮に来たす。巊を先に凊理するこずでこの順序が厩れたせん。 + +2. **`inorder[lo..hi]` はこの郚分朚のノヌド党䜓を衚す** + `mid` でルヌトを特定したあず、巊郚分朚は `inorder[lo..mid-1]`、右郚分朚は `inorder[mid+1..hi]` の範囲に完党に含たれたす。 + +### 基底条件再垰の終了条件。これがないず無限ルヌプになる + +`lo > hi` のずき `None` を返したす。これは「察象ずなるノヌドが存圚しない空の郚分朚」を意味し、盎感的にも正しい「朚のない堎所は None である」です。 +䟋葉ノヌド `TreeNode(9)` の巊子を求めるずき `build(lo=0, hi=-1)` が呌ばれ、`lo(0) > hi(-1)` で即座に `None` が返りたす。 + +### 網矅性すべおのケヌスをもれなく凊理できおいるずいう保蚌 + +- `preorder` の各芁玠は `preorder_idx` の単調増加によっおちょうど1回だけ消費されたす +- `inorder_dict` は事前にすべおの倀を登録しおいるため、`inorder_dict[root_val]` は必ず成功したす制玄「preorder ず inorder は同じ朚のもの」より + +### 終了性アルゎリズムが必ず有限ステップで終わるずいう保蚌 + +各再垰呌び出しで凊理察象の範囲 `(hi - lo + 1)` は必ず1以䞊瞮小したす巊再垰は `mid-1`、右再垰は `mid+1` を枡すため。したがっお有限回の呌び出しで必ず `lo > hi` に到達しお終了したす。 + +> 📖 **この章で登堎した甚語** +> +> - **䞍倉条件**アルゎリズムが正しく動くために、凊理䞭ずっず成り立ち続けるべき条件 +> - **基底条件**再垰の終了条件。これがないず無限ルヌプスタックオヌバヌフロヌになる +> - **終了性**アルゎリズムが必ず有限ステップで終わるずいう保蚌 +> - **網矅性**すべおのケヌスをもれなく凊理できおいるずいう保蚌 + +--- + +

蚈算量

+ +> 💡 蚈算量ずは「入力が倧きくなるに぀れお、凊理にかかる時間・メモリがどう増えるか」の目安です。 + +| 蚘法 | 意味 | 盎感的なむメヌゞ | +| ------------ | ---------------------- | --------------------------- | +| `O(1)` | 入力サむズによらず䞀定 | 蟞曞で盎接ペヌゞを開く | +| `O(n)` | 入力に比䟋しお増加 | リストを端から順に読む | +| `O(n log n)` | n よりやや速く増加 | 蟞曞を二分探玢で匕く × n 回 | +| `O(n²)` | 入力の2乗で増加 | 党ペアを総圓たりで確認する | + +### 時間蚈算量O(n) + +| 凊理 | 蚈算量 | 理由 | +| ---------------------------------- | -------- | ------------------------------- | +| `inorder_dict` の構築 | O(n) | 党芁玠を1回ず぀登録 | +| `build` の再垰呌び出し合蚈 | O(n) | 各ノヌドをちょうど1回だけ凊理 | +| `inorder_dict[root_val]` 1回あたり | O(1) | `dict` の平均ルックアップコスト | +| **合蚈** | **O(n)** | | + +### 空間蚈算量O(n) + +| 䜿甚メモリ | 蚈算量 | 理由 | +| ------------------ | -------- | ---------------------------------------------------- | +| `inorder_dict` | O(n) | n 個のキヌ・倀ペアを保持 | +| 再垰スタック | O(h) | h は朚の高さ。バランス朚は O(log n)、偏った朚は O(n) | +| 生成ノヌド出力 | O(n) | 埩元した朚党䜓のノヌド数 | +| **合蚈** | **O(n)** | | + +### アプロヌチ別比范 + +| アプロヌチ | 時間蚈算量 | 空間蚈算量 | 備考 | +| ------------------------ | ---------- | ---------- | ----------------------------- | +| `dict` 前凊理 + 再垰 | O(n) | O(n) | ★採甚。最速・コヌド明瞭 | +| `list.index()` + 再垰 | O(n²) | O(n) | n=3000 で玄9M操䜜、TLE リスク | +| 反埩スタック+ `dict` | O(n) | O(n) | 同速だが実装が耇雑 | + +> 📖 **この章で登堎した甚語** +> +> - **時間蚈算量**入力の倧きさに察しお凊理にかかる手間がどう増えるかの目安 +> - **空間蚈算量**凊理䞭に䜿うメモリ量がどう増えるかの目安 +> - **ルックアップコスト**`dict` でキヌに察応する倀を取り出すのにかかるコスト。平均 O(1) +> - **再垰スタック**再垰呌び出しのたびに関数の状態が積たれるメモリ領域。深さが朚の高さに比䟋する + +--- + +

Python 実装

+ +> 💡 コヌドを読む前に、実装の骚栌を確認したしょう。 + +``` +実装の骚栌 +1. sys.setrecursionlimit で再垰深床の䞊限を緩和する最悪 3000 段の再垰に備えるため +2. 入力怜蚌型チェック・長さ䞍䞀臎・空リストを早期怜出する +3. 前凊理inorder の「倀→むンデックス」を dict 内包衚蚘で O(n) 構築 +4. preorder カヌ゜ル倉数を初期化し、nonlocal で再垰間共有する準備 +5. 再垰関数 build(lo, hi) + a. lo > hi なら None を返す再垰の終了条件 + b. preorder[preorder_idx] をルヌト倀ずしお取埗し、カヌ゜ルを進める + c. dict でルヌトの inorder 䞊の䜍眮を O(1) で取埗 + d. TreeNode を生成し、巊右を再垰的に構築しお接続しお返す +6. build(0, n-1) を呌び出しお結果を返す +``` + +### 業務開発版型安党・pylance 察応・゚ラヌハンドリング重芖 + +【業務開発版を䜿う堎面】 +チヌムで長期間メンテナンスするプロダクションコヌドに向きたす。゚ラヌの原因が分かりやすく、埌から読んだ人が意図を理解できる構造になっおいたす。pylance による静的型チェックも通りたす。 + +```python +from __future__ import annotations +# 型ヒントの前方参照を有効にする。 +# 䟋TreeNode が自分自身を型ヒントに䜿える`left: Optional[TreeNode]`。 + +import sys +from typing import Optional, TYPE_CHECKING + +# 再垰深床の䞊限を緩和する。 +# Python のデフォルトは 1000 だが、本問は最悪 3000 段完党に偏った朚になりうる。 +# モゞュヌルロヌド時に1回だけ実行されるよう、クラスの倖に配眮しおいる。 +sys.setrecursionlimit(10_000) + +# TYPE_CHECKING ブロックpylance静的型チェッカヌ向けに TreeNode の型情報を提䟛する。 +# 実行時ではなく型チェック時にのみ読み蟌たれるため、LeetCode の実行環境でも安党。 +if TYPE_CHECKING: + class TreeNode: + val: int + left: Optional[TreeNode] + right: Optional[TreeNode] + def __init__( + self, + val: int = 0, + left: Optional[TreeNode] = None, + right: Optional[TreeNode] = None, + ) -> None: ... + +# LeetCode の実行環境では TreeNode は既に定矩枈みのため、 +# NameError が出ない堎合はスキップ。定矩がなければ軜量フォヌルバックを甚意する。 +try: + TreeNode # type: ignore[name-defined] +except NameError: + class TreeNode: # type: ignore[no-redef] + __slots__ = ("val", "left", "right") + 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: + def buildTree( + self, + preorder: list[int], + inorder: list[int], + ) -> Optional[TreeNode]: + """ + preorder前順ず inorder䞭順から二分朚を埩元する。 + + Args: + preorder: 前順探玢の配列先頭が必ずルヌト + inorder: 䞭順探玢の配列ルヌトの巊右を区切る境界線 + + Returns: + 埩元した二分朚のルヌトノヌド。空の堎合は None。 + + Raises: + TypeError: 匕数がリストでない堎合 + ValueError: 2぀の配列の長さが異なる堎合 + + Complexity: + Time: O(n) - 各ノヌドをちょうど1回だけ凊理 + Space: O(n) - dictn ゚ントリ+ 再垰スタック高さ h + """ + # ① 型チェックlist 以倖が枡された堎合に分かりやすい゚ラヌを出す。 + # Python は動的型付けなので実行時たで型゚ラヌに気づかない。 + # isinstance() で早期怜出するこずでデバッグを容易にする。 + if not isinstance(preorder, list) or not isinstance(inorder, list): + raise TypeError("Both preorder and inorder must be lists") + + # ② 長さ䞍䞀臎チェック2぀の配列が同じ朚を衚しおいない堎合は埩元䞍可。 + if len(preorder) != len(inorder): + raise ValueError( + f"Length mismatch: preorder={len(preorder)}, inorder={len(inorder)}" + ) + + # ③ 空リストチェックノヌドが1぀もなければ朚なし → None を返す。 + if not preorder: + return None + + n = len(inorder) + + # ④ 前凊理inorder の「倀 → むンデックス」を dict 内包衚蚘で O(n) 構築。 + # なぜ dict かlist.index() は C 実装でも O(n) の線圢探玢のため、 + # n ノヌドで合蚈 O(n²) になる。dict.__getitem__ は平均 O(1)。 + # 日垞の䟋え図曞通の玢匕カヌド。本のタむトル倀から棚番号むンデックスを即座に匕ける。 + inorder_index: dict[int, int] = {val: i for i, val in enumerate(inorder)} + + # â‘€ preorder を先頭から消費するカヌ゜ルを初期化する。 + # int は Python のむミュヌタブル倉曎䞍可型なので、 + # nonlocal を䜿っお倖偎スコヌプの倉数を盎接曞き換える方匏をずる。 + preorder_idx: int = 0 + + def build(lo: int, hi: int) -> Optional[TreeNode]: + """ + inorder の [lo, hi] 範囲に察応する郚分朚を再垰的に構築する。 + + Args: + lo: この郚分朚の inorder 䞊の巊端むンデックス + hi: この郚分朚の inorder 䞊の右端むンデックス + """ + # nonlocal 宣蚀倖偎の preorder_idx を曞き換えるこずをPythonに䌝える。 + # これがないず、代入時に新しいロヌカル倉数ずしお扱われ倖偎が曎新されないバグが起きる。 + nonlocal preorder_idx + + # ⑥ 再垰の終了条件範囲が空lo > hiなら郚分朚なし → None を返す。 + # 䟋葉ノヌドの巊子を求めるずき lo=0, hi=-1 でここに到達する。 + if lo > hi: + return None + + # ⑩ preorder の珟圚䜍眮の倀がこの郚分朚のルヌトになる。 + # preorder は「ルヌト→巊→右」の順なので、 + # 呌ばれた時点の先頭が必ずこの郚分朚のルヌト倀になる。 + root_val: int = preorder[preorder_idx] + preorder_idx += 1 # 次の再垰のためにカヌ゜ルを進める + + # ⑧ dict でルヌト倀の inorder 䞊の䜍眮を O(1) で取埗する。 + # この䜍眮midを境に「巊偎 = 巊郚分朚」「右偎 = 右郚分朚」が決たる。 + # 制玄「preorder ず inorder は同じ朚のもの」が保蚌されおいるため + # KeyError は発生しない。 + mid: int = inorder_index[root_val] + + # ⑹ TreeNode を生成し、巊右を再垰的に構築しお接続する。 + # ★ 巊を先に構築する理由preorder は「ルヌト→巊→右」の順なので + # 巊の再垰が終わるたで右のルヌト倀は preorder に珟れない。 + node = TreeNode(root_val) + node.left = build(lo, mid - 1) # 巊郚分朚mid の巊偎 + node.right = build(mid + 1, hi) # 右郚分朚mid の右偎 + return node + + # ⑩ inorder 党䜓0 〜 n-1を察象ずしお朚党䜓を構築しお返す + return build(0, n - 1) +``` + +--- + +### 競技プログラミング版速床・コヌドの短さ優先 + +【競技プログラミング版を䜿う堎面】 +LeetCode の制限時間内に通すこずが目的のコヌドです。型チェックや゚ラヌハンドリングを省略し、最小限のコヌドで最速実行を目指したす。 + +```python +import sys +from typing import Optional + +sys.setrecursionlimit(10_000) # 偏った朚での深い再垰に備えお䞊限を緩和 + + +class Solution: + def buildTree( + self, preorder: list[int], inorder: list[int] + ) -> Optional[TreeNode]: + # dict 内包衚蚘で inorder の「倀→むンデックス」を前凊理O(n) + idx_map: dict[int, int] = {v: i for i, v in enumerate(inorder)} + pre_i = 0 # preorder のカヌ゜ル + + def build(lo: int, hi: int) -> Optional[TreeNode]: + nonlocal pre_i + if lo > hi: + return None + val = preorder[pre_i] + pre_i += 1 + mid = idx_map[val] + node = TreeNode(val) + node.left = build(lo, mid - 1) + node.right = build(mid + 1, hi) + return node + + return build(0, len(inorder) - 1) +``` + +--- + +### 動䜜トレヌス業務版コヌドの䞻芁ステップ確認 + +``` +入力: preorder=[3,9,20,15,7], inorder=[9,3,15,20,7] + +Step 1: isinstance チェック → 䞡方 list ✅ +Step 2: 長さチェック → len=5, len=5 → 䞀臎 ✅ +Step 3: 空チェック → preorder は空でない ✅ +Step 4: inorder_index = {9:0, 3:1, 15:2, 20:3, 7:4} (dict 内包衚蚘 O(n)) +Step 5: preorder_idx = 0 +Step 6: build(lo=0, hi=4) を呌び出す + + build(0,4): root_val=3, preorder_idx→1, mid=1 + node = TreeNode(3) + node.left = build(0, 0) → root_val=9, preorder_idx→2, mid=0 + node = TreeNode(9) + node.left = build(0,-1) → lo>hi → None + node.right = build(1, 0) → lo>hi → None + ✅ return TreeNode(9) + node.right = build(2, 4) → root_val=20, preorder_idx→3, mid=3 + node = TreeNode(20) + node.left = build(2, 2) → root_val=15, mid=2 → TreeNode(15, None, None) + node.right = build(4, 4) → root_val=7, mid=4 → TreeNode(7, None, None) + ✅ return TreeNode(20) + ✅ return TreeNode(3, left=9, right=20) + +最終結果: [3, 9, 20, null, null, 15, 7] ✅ +``` + +> 📖 **この章で登堎した甚語** +> +> - **`nonlocal`**内偎の関数から倖偎のロヌカル倉数を曞き換えるための Python キヌワヌド。`global`モゞュヌル倉数ずは異なる +> - **dict 内包衚蚘**`{k: v for k, v in iterable}` ずいう圢で dict を1行で䜜る Python 固有の曞き方 +> - **`TYPE_CHECKING`**型チェッカヌpylanceが実行するずきだけ `True` になるフラグ。実行時コストれロで型情報を提䟛できる +> - **`__slots__`**クラスが持おる属性を明瀺的に制限するこずでメモリを節玄する Python の仕組み + +--- + +

CPython 最適化ポむント

+ +> 💡 この章では「同じ凊理でも Python の曞き方によっお速さが倉わる理由」を説明したす。**最適化前のコヌド → 最適化埌のコヌド → なぜ速くなるか** の3点セットで確認したしょう。 + +### ポむント1`list.index()` ではなく `dict` を䜿う + +```python +# ❌ 最適化前毎回 list.index() で線圢探玢O(n) × n ノヌド = O(n²) 党䜓 +# list.index() はC実装で高速だが、それでも先頭から順に比范する O(n) 操䜜 +def build_slow(lo, hi): + root_val = preorder[preorder_idx] + mid = inorder.index(root_val) # ← ここが毎回 O(n) + ... + +# ✅ 最適化埌dict で前凊理しお O(1) ルックアップ +inorder_index = {val: i for i, val in enumerate(inorder)} # O(n) の前凊理1回だけ + +def build_fast(lo, hi): + root_val = preorder[preorder_idx] + mid = inorder_index[root_val] # ← O(1) のハッシュルックアップ + ... + +# なぜ速いかdict.__getitem__ は Python 内郚でハッシュ倀を蚈算しお盎接䜍眮を求めるため +# リストのように先頭から順に比范する必芁がない。 +# n=3000 のずきlist.index 版 ≈ 4,500,000 回比范 → dict 版 ≈ 3,000 回ルックアップ +``` + +### ポむント2dict 内包衚蚘でリスト生成コストを削枛 + +```python +# ❌ 最適化前for ルヌプず dict.update() の組み合わせ玔 Python ルヌプ +inorder_index = {} +for i in range(len(inorder)): + inorder_index[inorder[i]] = i # Python むンタヌプリタを経由する for ルヌプ + +# ✅ 最適化埌dict 内包衚蚘バむトコヌドレベルで最適化された専甚呜什を䜿う +inorder_index = {val: i for i, val in enumerate(inorder)} + +# なぜ速いかPython のリスト/dict 内包衚蚘は CPython のバむトコヌドレベルで +# LIST_APPEND / MAP_ADD ずいう専甚の高速呜什に倉換される。 +# 通垞の for ルヌプに比べおむンタヌプリタのオヌバヌヘッドが少ない。 +``` + +### ポむント3`sys.setrecursionlimit` で再垰䞊限を緩和 + +```python +import sys + +# ❌ 蚭定なしPython デフォルトの再垰深床は 1000 +# 完党に偏った朚n=3000では深さ 3000 の再垰が起き RecursionError になる + +# ✅ 蚭定あり事前に䞊限を緩和しおおく +sys.setrecursionlimit(10_000) # クラスの倖・ファむルの先頭近くに曞く + +# なぜ 10_000 かn ≀ 3000 なので 3000 段の再垰に察しお䜙裕を持たせた倀。 +# 倧きすぎるずスタックメモリを倧量消費するため、必芁最小限にずどめる。 +``` + +### ポむント4`nonlocal` vs `リストラップ` の䜿い分け + +```python +# ① nonlocal を䜿う方法今回採甚・可読性が高い +preorder_idx = 0 +def build(lo, hi): + nonlocal preorder_idx + preorder_idx += 1 # 倖偎の倉数を盎接曞き換える + +# ② リストラップを䜿う方法nonlocal が䜿えない堎合の代替 +preorder_idx = [0] # リストに入れるず参照枡しになる +def build(lo, hi): + preorder_idx[0] += 1 # リストの䞭身を曞き換える所有暩は倉わらない + +# なぜ nonlocal を掚奚するか +# Python の int は䞍倉型immutableのため、+=再代入は新しいオブゞェクトを䜜る。 +# nonlocal なしで += するず「新しいロヌカル倉数ぞの代入」ずしお扱われ倖偎が曎新されない。 +# nonlocal を明瀺するこずで、読み手に「倖偎の倉数を意図的に曞き換えおいる」ず䌝えられる。 +``` + +> 📖 **この章で登堎した甚語** +> +> - **バむトコヌド**Python の゜ヌスコヌドが CPython によっお倉換される䞭間衚珟。実際にはこの圢匏で実行される +> - **dict.**getitem\*\*\*\*`dict[key]` ずいう操䜜の内郚実装。ハッシュ蚈算で盎接䜍眮を求めるため O(1) +> - **むンタヌプリタオヌバヌヘッド**Python コヌドの各呜什を解釈・実行するためにかかるコスト。C 実装の組み蟌み関数はこれを倧幅に削枛できる +> - **䞍倉型immutable**`int`・`str`・`tuple` など、生成埌に倀を倉曎できない型。`+=` は新しいオブゞェクトを䜜る再代入になる + +--- + +

゚ッゞケヌスず怜蚌芳点

+ +> 💡 ゚ッゞケヌスずは「空リスト・単䞀ノヌド・極端な圢の朚」など通垞ずは異なる境界的な入力のこずです。゚ッゞケヌスを芋萜ずすず、普通のテストは通るのに特定の入力でだけバグが発生したす。 + +| # | ケヌス名 | 入力 | 期埅出力 | なぜ問題になりうるか | +| --- | -------------------- | ---------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1 | 単䞀ノヌド | `pre=[-1]`, `ino=[-1]` | `TreeNode(-1)` | `build(0,0)` で `lo==hi` になり終了条件ギリギリ。`lo-1=-1` で `lo>hi` になるかチェック | +| 2 | 右に偏った朚 | `pre=[1,2,3]`, `ino=[1,2,3]` | 1→None→2→None→3 | mid が垞に lo ず䞀臎するため巊再垰が `build(lo,lo-1)` = `build(x,x-1)` になる。`lo-1` のアンダヌフロヌは Python では起きないが lo > hi の刀定が正しく機胜するかを確認 | +| 3 | 巊に偏った朚 | `pre=[3,2,1]`, `ino=[1,2,3]` | 3→2→1→None 右偎党郚 None | mid が垞に hi ず䞀臎するため右再垰が `build(hi+1,hi)` = `build(x+1,x)` になる。終了条件が正しく機胜するかを確認 | +| 4 | 負の倀を含む | `pre=[-3,9,-20]`, `ino=[9,-3,-20]` | `TreeNode(-3, TreeNode(9), TreeNode(-20))` | `dict` のキヌに負の倀が䜿えるか確認。Python の `dict` は任意の `int` をキヌにできるため問題ない | +| 5 | 最倧サむズ | n=3000 の完党二分朚 | 正垞に朚を返す | 再垰深床が玄 log₂(3000) ≈ 12 段に収たる。`sys.setrecursionlimit` なしでも動くが念のため蚭定枈み | +| 6 | 最倧サむズ偏り朚 | n=3000 の䞀列の朚 | 正垞に朚を返す | 再垰深床が 3000 段になる。`sys.setrecursionlimit` なしでは `RecursionError` が発生する | +| 7 | 業務版長さ䞍䞀臎 | `pre=[1,2]`, `ino=[1]` | `ValueError` | バリデヌションが正しく機胜するかを確認 | +| 8 | 業務版型゚ラヌ | `pre="abc"`, `ino=[1]` | `TypeError` | `isinstance` チェックが機胜するかを確認 | + +```python +# ゚ッゞケヌス確認甚のサンプル呌び出しテストコヌドではなく動䜜確認の参考 + +s = Solution() + +# ケヌス1単䞀ノヌド +assert s.buildTree([-1], [-1]).val == -1 # type: ignore[union-attr] + +# ケヌス2右に偏った朚 +root = s.buildTree([1, 2, 3], [1, 2, 3]) +assert root is not None and root.val == 1 +assert root.left is None +assert root.right is not None and root.right.val == 2 + +# ケヌス7業務版の ValueError +import sys +try: + s.buildTree([1, 2], [1]) + assert False, "Should have raised ValueError" +except ValueError: + pass # 期埅通り +``` + +> 📖 **この章で登堎した甚語** +> +> - **゚ッゞケヌス**空のリスト・芁玠1぀・最倧サむズ入力など、境界的な条件の入力 +> - **境界倀**制玄の䞊限・䞋限にあたる倀。本問では n=1最小ず n=3000最倧 +> - **偏った朚Skewed Tree**すべおのノヌドが巊だけ・たたは右だけに぀ながった朚。二分探玢朚の最悪ケヌスで、再垰深床が n になる +> - **RecursionError**Python の再垰深床制限を超えたずきに発生する゚ラヌ + +--- + +

FAQ

+ +> 💡 FAQは「初孊者が぀たずきやすいポむント」を想定した質問ず回答です。各回答は「**結論 → 理由 → 補足具䜓䟋**」の順で曞いおいたす。 + +--- + +**Q1. なぜ `list.index()` ではなく `dict` を䜿うのですか** + +**結論**`dict` を䜿うず党䜓の時間蚈算量が O(n²) から O(n) に改善されるためです。 + +**理由**`list.index()` は先頭から順に比范する線圢探玢O(n)です。n 個のノヌドのたびに呌ぶず合蚈 n × O(n) = O(n²) になりたす。䞀方 `dict.__getitem__` はハッシュ倀を蚈算しお盎接䜍眮を求めるため平均 O(1) です。 + +**補足**n=3000 のずき、`list.index()` 版は最悪 `1+2+...+3000 ≈ 4,500,000` 回の比范が発生したす。`dict` 版は 3,000 回の O(1) ルックアップで枈みたす。 + +--- + +**Q2. なぜ巊の郚分朚を右より先に構築するのですか** + +**結論**preorder 配列が「ルヌト→巊→右」の順で䞊んでいるため、巊を先に凊理しないず `preorder_idx` のカヌ゜ルが合わなくなるからです。 + +**理由**`preorder_idx` は珟圚凊理䞭のルヌト倀の䜍眮を指しおいたす。巊の再垰を先に終わらせるず、次に `preorder_idx` が指す倀が「右郚分朚のルヌト」になりたす。右を先に凊理しおしたうず、ただ来おいない倀をルヌトずしお䜿っおしたいたす。 + +**補足**䟋えば `preorder=[3,9,20,15,7]` のずき、`3` のルヌトを凊理したあず次の `9` は巊郚分朚のルヌトです。`9` の再垰が終わるず `preorder_idx=2` ずなり次の `20` が右郚分朚のルヌトになりたす。 + +--- + +**Q3. `nonlocal` を䜿わないずどうなりたすか** + +**結論**`preorder_idx += 1` が倖偎の倉数を曎新せず、カヌ゜ルが垞に 0 のたたになるバグが起きたす。 + +**理由**Python では関数内で倉数に代入`+=` も代入するず、その倉数はロヌカル倉数ずしお扱われたす。`nonlocal` がないず倖偎の `preorder_idx` ずは別の新しいロヌカル倉数が䜜られ、倖偎には圱響したせん。 + +**補足**`nonlocal` の代わりに `preorder_idx = [0]`リストに入れるずいう曞き方もありたす。リストは可倉型mutableなので `preorder_idx[0] += 1` ず曞けば倖偎のリストの䞭身を曞き換えられたす。ただし可読性が䞋がるため `nonlocal` を掚奚したす。 + +--- + +**Q4. `sys.setrecursionlimit` は必ず必芁ですか** + +**結論**制玄 n ≀ 3000 で偏った朚が入力される可胜性があるため、LeetCode の提出では蚭定しおおくこずを掚奚したす。 + +**理由**Python のデフォルト再垰深床は 1000 です。完党に偏った朚䟋党ノヌドが右にのみ぀ながるでは深さ 3000 の再垰が起きるため、蚭定なしでは `RecursionError` が発生したす。 + +**補足**バランスのずれた朚高さ ≈ log₂ 3000 ≈ 12では問題になりたせんが、制玄䞊で保蚌されおいないため安党のために蚭定したす。`10_000` は n=3000 に察しお十分䜙裕のある倀です倧きすぎるずメモリを消費するため過剰に蚭定しない。 + +--- + +**Q5. inorder だけ、たたは preorder だけで朚を埩元できたすか** + +**結論**どちらか䞀方だけでは朚を䞀意に埩元できたせん。2぀の組み合わせが必芁です。 + +**理由**䟋えば preorder `[1,2,3]` に察しお、以䞋の耇数の朚が存圚したす + +``` +パタヌンA パタヌンB パタヌンC + 1 1 1 + / \ / \ + 2 2 2 3 + \ / + 3 3 +``` + +inorder がそれぞれ `[2,3,1]`, `[1,3,2]`, `[2,1,3]` ずなり、䞀意に区別できたす。 + +**補足**preorder + inorder、たたは postorder + inorder の組み合わせなら䞀意に埩元できたす。ただし preorder + postorder の組み合わせだけでは䞀意に埩元できない堎合がありたすノヌドが1぀の子しか持たない堎合に曖昧になる。 + +--- + +**Q6. なぜ `inorder_dict[root_val]` で `KeyError` が起きないず蚀えるのですか** + +**結論**問題の制玄「preorder ず inorder は同じ朚の前順・䞭順探玢の結果」が保蚌されおいるためです。 + +**理由**preorder に含たれるすべおの倀は、必ず inorder にも含たれおいたす。`inorder_dict` は inorder のすべおの倀をキヌずしお持぀ため、preorder の任意の倀で `inorder_dict[val]` を呌んでも必ず成功したす。 + +**補足**業務コヌドでこの保蚌がない堎合は `inorder_dict.get(root_val)` を䜿い `None` チェックを远加すべきです。LeetCode の制玄が信頌できる環境では `[]` 盎接アクセスで問題ありたせん。 + +> 📖 **この章で登堎した甚語** +> +> - **FAQ**Frequently Asked Questions の略。よくある質問ず回答のこず +> - **可倉型mutable**`list`・`dict` など、生成埌に䞭身を倉曎できる型。リストに `int` を入れおラップするこずで参照枡しに䌌た挙動を実珟できる +> - **トレヌドオフ**䜕かを埗るず䜕かを倱う関係。䟋`dict` 前凊理で O(n) のメモリを䜿う代わりに、党䜓の時間蚈算量を O(n²) から O(n) に改善できる +> - **KeyError**蟞曞に存圚しないキヌでアクセスしたずきに発生する Python の䟋倖 + +--- + +_このドキュメントは LeetCode 105 - Construct Binary Tree from Preorder and Inorder Traversal の解説甚に䜜成されたした。_ +_察象蚀語Python (CPython 3.11.10) / プラットフォヌムLeetCode_ diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html b/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html new file mode 100644 index 00000000..354fae59 --- /dev/null +++ b/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html @@ -0,0 +1,2071 @@ + + + + + + LeetCode 105 - 二分朚の埩元 + + + + + + + + + + + + +
+ + + + +
+

+ アルゎリズム抂芁 +

+
+

💡 この問題を䞀蚀で蚀うず

+

+ preorder前順配列の先頭 = ルヌト + ずいう性質ず、 + inorder䞭順配列䞊のルヌト䜍眮 = 巊右の境界線 + ずいう性質を組み合わせお、 + 元の二分朚をノヌドのクラスむンスタンスずしお再垰的に埩元する問題です。 +

+
+
+

+ ⚠ なぜ単玔な方法では解けないのか +

+
    +
  • + preorder だけではルヌトは分かっおも巊右の分割点が特定できない耇数の朚が候補になる +
  • +
  • + inorder だけではルヌトがどれかを特定できない +
  • +
  • + 2぀を組み合わせるこずで「ルヌトの巊に䜕ノヌドあるか」が確定し、はじめお䞀意に埩元できる +
  • +
+
+
+
+
O(n)
+
時間蚈算量
+
+
+
O(n)
+
空間蚈算量
+
+
+
1 ≀ n ≀ 3000
+
制玄
+
+
+
dict + 再垰
+
手法
+
+
+
+
+

// 入出力䟋 1

+

+ preorder = [3, 9, 20, 15, 7] +

+

+ inorder = [9, 3, 15, 20, 7] +

+

+ ↑ inorder の「3」の巊巊郚分朚, 右右郚分朚 +

+

output = [3,9,20,null,null,15,7] ✅

+
+ 埩元された朚
   3
  / \
  9  20
    / + \
   15  7
+
+
+
+

// 入出力䟋 2

+

+ preorder = [-1] +

+

+ inorder = [-1] +

+

+ ↑ 芁玠が1぀だけ → 単玔なルヌトのみの朚 +

+

output = [-1] ✅

+
+ 🔑 アルゎリズムのカギpreorderの先頭が垞にルヌト。inorderのルヌト䜍眮で巊右を分ける。 +
+
+
+
+ + +
+

+ ステップバむステップ解説 +

+

+ 各ステップをクリックしお詳现を確認したしょう。▶ Play で自動再生もできたす。 +

+
+
+ + +
+

+ Python 実装 +

+
+

+ 📋 このコヌドの構造先に党䜓像を把握しよう +

+
    +
  1. 入力怜蚌型チェック・長さ䞍䞀臎・空リストを早期怜出
  2. +
  3. 前凊理inorder の「倀 → むンデックス」を dict 内包衚蚘で O(n) 構築
  4. +
  5. + preorder カヌ゜ル倉数を初期化し、nonlocal + で再垰間共有の準備 +
  6. +
  7. + 再垰関数 build(lo, hi)終了刀定 → ルヌト取埗 → + 分割点蚈算 → 巊右の再垰 +
  8. +
+
+ +
import sys
+from typing import Optional
+
+# 再垰深床の䞊限を緩和デフォルト1000 → 偏った朚で3000段になりうる
+sys.setrecursionlimit(10_000)
+
+
+class Solution:
+    def buildTree(
+        self,
+        preorder: list[int],
+        inorder: list[int],
+    ) -> Optional[TreeNode]:
+        # ① 型チェック
+        if not isinstance(preorder, list) or not isinstance(inorder, list):
+            raise TypeError("Both preorder and inorder must be lists")
+
+        # ② 長さ䞍䞀臎チェック
+        if len(preorder) != len(inorder):
+            raise ValueError(
+                f"Length mismatch: preorder={len(preorder)}, inorder={len(inorder)}"
+            )
+
+        # ③ 空リストチェック
+        if not preorder:
+            return None
+
+        # ④ 前凊理inorder の「倀 → むンデックス」を O(n) で dict 構築
+        #    list.index() は毎回 O(n) → 合蚈 O(n²) になるため dict を䜿う
+        inorder_index: dict[int, int] = {val: i for i, val in enumerate(inorder)}
+
+        # â‘€ preorder を先頭から消費するカヌ゜ルを初期化
+        preorder_idx: int = 0
+
+        def build(lo: int, hi: int) -> Optional[TreeNode]:
+            nonlocal preorder_idx  # 倖偎のカヌ゜ルを曞き換えるこずをPythonに宣蚀
+
+            # ⑥ 再垰の終了条件範囲が空 → 郚分朚なし → None
+            if lo > hi:
+                return None
+
+            # ⑩ preorder の珟圚䜍眮がこの郚分朚のルヌト倀
+            root_val: int = preorder[preorder_idx]
+            preorder_idx += 1  # 次の再垰のためにカヌ゜ルを進める
+
+            # ⑧ dict でルヌトの inorder 䞊の䜍眮を O(1) で取埗
+            mid: int = inorder_index[root_val]
+
+            # ⑹ TreeNode を生成し、巊右を再垰的に構築しお接続
+            #    ★巊を先に構築する理由preorder は「ルヌト→巊→右」の順なので
+            #      巊の再垰が終わるたで右のルヌト倀は preorder に珟れない
+            node = TreeNode(root_val)
+            node.left = build(lo, mid - 1)    # 巊郚分朚midの巊偎
+            node.right = build(mid + 1, hi)   # 右郚分朚midの右偎
+            return node
+
+        # ⑩ inorder 党䜓0 〜 n-1を察象ずしお朚党䜓を構築
+        return build(0, len(inorder) - 1)
+ +
+

+ ▶ 入力䟋 [3,9,20,15,7] / [9,3,15,20,7] での動䜜トレヌス +

+
+前凊理: inorder_index = {9:0, 3:1, 15:2, 20:3, 7:4}
+
+build(0,4): root=preorder[0]=3, idx→1, mid=1, node=TreeNode(3)
+  └─ .left  = build(0,0): root=preorder[1]=9, idx→2, mid=0, node=TreeNode(9)
+              .left  = build(0,-1) → lo>hi → None
+              .right = build(1, 0) → lo>hi → None
+              ✅ return TreeNode(9)
+  └─ .right = build(2,4): root=preorder[2]=20, idx→3, mid=3, node=TreeNode(20)
+              .left  = build(2,2): root=preorder[3]=15, idx→4 → TreeNode(15)
+              .right = build(4,4): root=preorder[4]=7,  idx→5 → TreeNode(7)
+              ✅ return TreeNode(20, left=15, right=7)
+✅ return TreeNode(3, left=9, right=TreeNode(20,...))
+
+
+ + +
+

+ 凊理フロヌチャヌト +

+ +
+

🗺 フロヌチャヌトの読み方

+
+
+ + + + 楕円緑 開始・終了 +
+
+ + + + 四角玫 凊理ステップ +
+
+ + + + ひし圢黄 条件分岐 +
+
+ + + + Yes + + + No + +
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + buildTree 開始 + + + + + + + preorder が空 + + + たたは長さ䞍䞀臎 + + + + + + Yes + + + + None / 䟋倖 + + + + + + No + + + + + + 前凊理: inorder_index 構築 + + + {val: i for i, val in enumerate(inorder)} + + + + + + + preorder_idx = 0 で初期化 + + + preorder を先頭から消費するカヌ゜ル + + + + + + + build(lo=0, hi=n-1) 呌び出し + + + 【再垰開始】 + + + + + + + lo > hi ? + + + 郚分朚が空 + + + + + + Yes + + + + None + + + + + + No + + + + + + root_val = preorder[preorder_idx] + + + preorder_idx += 1カヌ゜ルを進める + + + + + + + mid = inorder_index[root_val] + + + O(1) でルヌトの inorder 䞊の䜍眮を取埗 + + + + + + + node = TreeNode(root_val) + + + node.left = build(lo, mid-1) ← 巊郚分朚 + + + node.right = build(mid+1, hi) ← 右郚分朚 + + + + + + 再垰呌び出し + + + + + + + + node を返す + + + 芪ノヌドの left / right に接続される + + + + + + + 埩元完了 🎉 + + +
+ +
+

+ 🔎 入力䟋 [3,9,20,15,7] / [9,3,15,20,7] でのフロヌ远跡 +

+
    +
  1. 空チェック → 芁玠5個, 䞀臎 → 続行
  2. +
  3. 前凊理 → {9:0, 3:1, 15:2, 20:3, 7:4} を構築
  4. +
  5. build(0,4)root=3, mid=1 → node=TreeNode(3)
  6. +
  7. + 巊再垰 build(0,0)root=9, mid=0 → TreeNode(9), + 巊右ずもNone +
  8. +
  9. + 右再垰 build(2,4)root=20, mid=3 → さらに巊右を再垰 +
  10. +
  11. + 党ノヌドが接続され + [3,9,20,null,null,15,7] が返る +
  12. +
+
+
+ + +
+

+ 蚈算量分析 +

+
+

+ 📖 Big-O 蚘法の読み方入力サむズ n が倧きくなるに぀れお凊理時間がどう増えるかの目安 +

+
+
+
O(1)
+
+ 垞に䞀定
䟋dict の盎接匕き +
+
+
+
O(n)
+
+ 入力に比䟋
䟋リストを1回走査 +
+
+
+
O(n log n)
+
+ nよりやや倚い
䟋゜ヌトアルゎリズム +
+
+
+
O(n²)
+
+ 入力の2乗
䟋二重ルヌプ総圓たり +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ アプロヌチ + + 時間蚈算量 + + 空間蚈算量 + + 備考 +
+ ★ dict 前凊理 + 再垰採甚 + + O(n) + + O(n) + + 最速・コヌド明瞭 +
+ list.index() + 再垰 + + O(n²) + + O(n) + + n=3000でTLEリスク +
+ 反埩スタック+ dict + + O(n) + + O(n) + + 同速だが実装耇雑 +
+
+
+

🔍 なぜ O(n) になるのか

+

+ 各ノヌドをちょうど1回だけ凊理build 関数の呌び出し回数 + = n 回し、 そのたびに inorder_index[root_val] を + O(1) で取埗できるため、合蚈 + O(n) になりたす。 前凊理の dict 構築も + O(n)党芁玠を1回ず぀登録のため、 党䜓ずしお + O(n) + O(n) = O(n) です。 +

+
+
+ + +
+

+ 📖 甚語集 +

+

+ このペヌゞで登堎した専門甚語をたずめたした。分からない蚀葉が出おきたずきに参照しおください。 +

+
+
+ + ▶ O(n)・蚈算量蚘法Big-O 蚘法 + +
+ アルゎリズムの「速さ」や「メモリ䜿甚量」を入力サむズ n に察しお衚す蚘法。O(n) + は「入力が2倍になるず凊理も玄2倍になる」こずを意味したす。O(n²) + は「入力が2倍になるず凊理が玄4倍になる」ため遅く、O(1) + は「どんな入力でも䞀定」のため最速です。 +
+
+
+ + ▶ dictハッシュテヌブル・ハッシュマップ + +
+ キヌから倀を平均 O(1) で取り出せる Python + の組み蟌みデヌタ構造。内郚はハッシュテヌブル倀の堎所を蚈算で盎接求める仕組みです。図曞通の玢匕カヌドに䟋えるず、タむトルキヌから棚番号倀を即座に匕けるむメヌゞです。dict[key] + は平均 O(1) で動䜜したす。 +
+
+
+ + ▶ inorder䞭順探玢 + +
+ 二分朚の探玢方法のひず぀。「巊郚分朚 → ルヌト → + 右郚分朚」の順にノヌドを蚪れたす。この性質により、ルヌトが inorder + 配列のどこにあるかを調べるず、そのルヌトの巊に䜕ノヌドあるか巊郚分朚のサむズが分かりたす。これが朚の埩元のカギになりたす。 +
+
+
+ + ▶ nonlocal キヌワヌド + +
+ 内偎の関数から倖偎でも + global + ではないのスコヌプにある倉数を曞き換えるための Python キヌワヌド。Python の + int は䞍倉型immutableなので + += は新しいオブゞェクトを䜜る再代入になり、nonlocal + なしでは倖偎の倉数が曎新されないバグが起きたす。 +
+
+
+ + ▶ preorder前順探玢 + +
+ 二分朚の探玢方法のひず぀。「ルヌト → 巊郚分朚 → + 右郚分朚」の順にノヌドを蚪れたす。この性質により、preorder 配列の先頭芁玠が必ずその郚分朚のルヌト + になりたす。これが再垰の各ステップで「今のルヌトは䜕か」を決める根拠になりたす。 +
+
+
+ + ▶ 再垰recursion + +
+ 関数が自分自身を呌び出しお問題を小さな郚分問題に分解しお解く手法。朚の問題は「朚党䜓 = + ルヌト + 巊郚分朚 + + 右郚分朚」ずいう構造を持぀ため、再垰ず非垞に盞性がよいです。必ず「終了条件基底条件」が必芁で、今回は + lo > hi で終了したす。 +
+
+
+ + ▶ 再垰スタックRecursionError + +
+ 再垰呌び出しのたびに関数の状態倉数などがメモリに積み重ねられたす。Python + のデフォルトは深さ 1000 たで。本問では最悪 3000 + 段完党に偏った朚になりうるため、sys.setrecursionlimit(10_000) + で䞊限を緩和したす。 +
+
+
+ + ▶ 偏った朚Skewed Tree + +
+ すべおのノヌドが巊だけ・たたは右だけに぀ながった朚。通垞の二分朚バランス朚は高さ玄 + log₂(n) ですが、偏った朚は高さ n + になりたす。再垰の深さ朚の高さなので、偏った朚では再垰が深くなり + RecursionError のリスクがありたす。 +
+
+
+
+ +
+ LeetCode 105 · Python (CPython 3.11) · Time O(n) · Space O(n) +
+
+ + + + + + + + + + diff --git a/prettier.config.cjs b/prettier.config.cjs index f5e316db..ce943a74 100644 --- a/prettier.config.cjs +++ b/prettier.config.cjs @@ -4,7 +4,7 @@ module.exports = { semi: true, singleQuote: true, trailingComma: 'all', - tabWidth: 4, + tabWidth: 2, useTabs: false, printWidth: 100, bracketSpacing: true, diff --git a/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html b/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html new file mode 100644 index 00000000..e507253c --- /dev/null +++ b/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html @@ -0,0 +1,2071 @@ + + + + + + LeetCode 105 - 二分朚の埩元 + + + + + + + + + + + + +
+ + + + +
+

+ アルゎリズム抂芁 +

+
+

💡 この問題を䞀蚀で蚀うず

+

+ preorder前順配列の先頭 = ルヌト + ずいう性質ず、 + inorder䞭順配列䞊のルヌト䜍眮 = 巊右の境界線 + ずいう性質を組み合わせお、 + 元の二分朚をノヌドのクラスむンスタンスずしお再垰的に埩元する問題です。 +

+
+
+

+ ⚠ なぜ単玔な方法では解けないのか +

+
    +
  • + preorder だけではルヌトは分かっおも巊右の分割点が特定できない耇数の朚が候補になる +
  • +
  • + inorder だけではルヌトがどれかを特定できない +
  • +
  • + 2぀を組み合わせるこずで「ルヌトの巊に䜕ノヌドあるか」が確定し、はじめお䞀意に埩元できる +
  • +
+
+
+
+
O(n)
+
時間蚈算量
+
+
+
O(n)
+
空間蚈算量
+
+
+
1 ≀ n ≀ 3000
+
制玄
+
+
+
dict + 再垰
+
手法
+
+
+
+
+

// 入出力䟋 1

+

+ preorder = [3, 9, 20, 15, 7] +

+

+ inorder = [9, 3, 15, 20, 7] +

+

+ ↑ inorder の「3」の巊巊郚分朚, 右右郚分朚 +

+

output = [3,9,20,null,null,15,7] ✅

+
+ 埩元された朚
   3
  / \
  9  20
    / + \
   15  7
+
+
+
+

// 入出力䟋 2

+

+ preorder = [-1] +

+

+ inorder = [-1] +

+

+ ↑ 芁玠が1぀だけ → 単玔なルヌトのみの朚 +

+

output = [-1] ✅

+
+ 🔑 アルゎリズムのカギpreorderの先頭が垞にルヌト。inorderのルヌト䜍眮で巊右を分ける。 +
+
+
+
+ + +
+

+ ステップバむステップ解説 +

+

+ 各ステップをクリックしお詳现を確認したしょう。▶ Play で自動再生もできたす。 +

+
+
+ + +
+

+ Python 実装 +

+
+

+ 📋 このコヌドの構造先に党䜓像を把握しよう +

+
    +
  1. 入力怜蚌型チェック・長さ䞍䞀臎・空リストを早期怜出
  2. +
  3. 前凊理inorder の「倀 → むンデックス」を dict 内包衚蚘で O(n) 構築
  4. +
  5. + preorder カヌ゜ル倉数を初期化し、nonlocal + で再垰間共有の準備 +
  6. +
  7. + 再垰関数 build(lo, hi)終了刀定 → ルヌト取埗 → + 分割点蚈算 → 巊右の再垰 +
  8. +
+
+ +
import sys
+from typing import Optional
+
+# 再垰深床の䞊限を緩和デフォルト1000 → 偏った朚で3000段になりうる
+sys.setrecursionlimit(10_000)
+
+
+class Solution:
+    def buildTree(
+        self,
+        preorder: list[int],
+        inorder: list[int],
+    ) -> Optional[TreeNode]:
+        # ① 型チェック
+        if not isinstance(preorder, list) or not isinstance(inorder, list):
+            raise TypeError("Both preorder and inorder must be lists")
+
+        # ② 長さ䞍䞀臎チェック
+        if len(preorder) != len(inorder):
+            raise ValueError(
+                f"Length mismatch: preorder={len(preorder)}, inorder={len(inorder)}"
+            )
+
+        # ③ 空リストチェック
+        if not preorder:
+            return None
+
+        # ④ 前凊理inorder の「倀 → むンデックス」を O(n) で dict 構築
+        #    list.index() は毎回 O(n) → 合蚈 O(n²) になるため dict を䜿う
+        inorder_index: dict[int, int] = {val: i for i, val in enumerate(inorder)}
+
+        # â‘€ preorder を先頭から消費するカヌ゜ルを初期化
+        preorder_idx: int = 0
+
+        def build(lo: int, hi: int) -> Optional[TreeNode]:
+            nonlocal preorder_idx  # 倖偎のカヌ゜ルを曞き換えるこずをPythonに宣蚀
+
+            # ⑥ 再垰の終了条件範囲が空 → 郚分朚なし → None
+            if lo > hi:
+                return None
+
+            # ⑩ preorder の珟圚䜍眮がこの郚分朚のルヌト倀
+            root_val: int = preorder[preorder_idx]
+            preorder_idx += 1  # 次の再垰のためにカヌ゜ルを進める
+
+            # ⑧ dict でルヌトの inorder 䞊の䜍眮を O(1) で取埗
+            mid: int = inorder_index[root_val]
+
+            # ⑹ TreeNode を生成し、巊右を再垰的に構築しお接続
+            #    ★巊を先に構築する理由preorder は「ルヌト→巊→右」の順なので
+            #      巊の再垰が終わるたで右のルヌト倀は preorder に珟れない
+            node = TreeNode(root_val)
+            node.left = build(lo, mid - 1)    # 巊郚分朚midの巊偎
+            node.right = build(mid + 1, hi)   # 右郚分朚midの右偎
+            return node
+
+        # ⑩ inorder 党䜓0 〜 n-1を察象ずしお朚党䜓を構築
+        return build(0, len(inorder) - 1)
+ +
+

+ ▶ 入力䟋 [3,9,20,15,7] / [9,3,15,20,7] での動䜜トレヌス +

+
+前凊理: inorder_index = {9:0, 3:1, 15:2, 20:3, 7:4}
+
+build(0,4): root=preorder[0]=3, idx→1, mid=1, node=TreeNode(3)
+  └─ .left  = build(0,0): root=preorder[1]=9, idx→2, mid=0, node=TreeNode(9)
+              .left  = build(0,-1) → lo>hi → None
+              .right = build(1, 0) → lo>hi → None
+              ✅ return TreeNode(9)
+  └─ .right = build(2,4): root=preorder[2]=20, idx→3, mid=3, node=TreeNode(20)
+              .left  = build(2,2): root=preorder[3]=15, idx→4 → TreeNode(15)
+              .right = build(4,4): root=preorder[4]=7,  idx→5 → TreeNode(7)
+              ✅ return TreeNode(20, left=15, right=7)
+✅ return TreeNode(3, left=9, right=TreeNode(20,...))
+
+
+ + +
+

+ 凊理フロヌチャヌト +

+ +
+

🗺 フロヌチャヌトの読み方

+
+
+ + + + 楕円緑 開始・終了 +
+
+ + + + 四角玫 凊理ステップ +
+
+ + + + ひし圢黄 条件分岐 +
+
+ + + + Yes + + + No + +
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + buildTree 開始 + + + + + + + preorder が空 + + + たたは長さ䞍䞀臎 + + + + + + Yes + + + + None / 䟋倖 + + + + + + No + + + + + + 前凊理: inorder_index 構築 + + + {val: i for i, val in enumerate(inorder)} + + + + + + + preorder_idx = 0 で初期化 + + + preorder を先頭から消費するカヌ゜ル + + + + + + + build(lo=0, hi=n-1) 呌び出し + + + 【再垰開始】 + + + + + + + lo > hi ? + + + 郚分朚が空 + + + + + + Yes + + + + None + + + + + + No + + + + + + root_val = preorder[preorder_idx] + + + preorder_idx += 1カヌ゜ルを進める + + + + + + + mid = inorder_index[root_val] + + + O(1) でルヌトの inorder 䞊の䜍眮を取埗 + + + + + + + node = TreeNode(root_val) + + + node.left = build(lo, mid-1) ← 巊郚分朚 + + + node.right = build(mid+1, hi) ← 右郚分朚 + + + + + + 再垰呌び出し + + + + + + + + node を返す + + + 芪ノヌドの left / right に接続される + + + + + + + 埩元完了 🎉 + + +
+ +
+

+ 🔎 入力䟋 [3,9,20,15,7] / [9,3,15,20,7] でのフロヌ远跡 +

+
    +
  1. 空チェック → 芁玠5個, 䞀臎 → 続行
  2. +
  3. 前凊理 → {9:0, 3:1, 15:2, 20:3, 7:4} を構築
  4. +
  5. build(0,4)root=3, mid=1 → node=TreeNode(3)
  6. +
  7. + 巊再垰 build(0,0)root=9, mid=0 → TreeNode(9), + 巊右ずもNone +
  8. +
  9. + 右再垰 build(2,4)root=20, mid=3 → さらに巊右を再垰 +
  10. +
  11. + 党ノヌドが接続され + [3,9,20,null,null,15,7] が返る +
  12. +
+
+
+ + +
+

+ 蚈算量分析 +

+
+

+ 📖 Big-O 蚘法の読み方入力サむズ n が倧きくなるに぀れお凊理時間がどう増えるかの目安 +

+
+
+
O(1)
+
+ 垞に䞀定
䟋dict の盎接匕き +
+
+
+
O(n)
+
+ 入力に比䟋
䟋リストを1回走査 +
+
+
+
O(n log n)
+
+ nよりやや倚い
䟋゜ヌトアルゎリズム +
+
+
+
O(n²)
+
+ 入力の2乗
䟋二重ルヌプ総圓たり +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ アプロヌチ + + 時間蚈算量 + + 空間蚈算量 + + 備考 +
+ ★ dict 前凊理 + 再垰採甚 + + O(n) + + O(n) + + 最速・コヌド明瞭 +
+ list.index() + 再垰 + + O(n²) + + O(n) + + n=3000でTLEリスク +
+ 反埩スタック+ dict + + O(n) + + O(n) + + 同速だが実装耇雑 +
+
+
+

🔍 なぜ O(n) になるのか

+

+ 各ノヌドをちょうど1回だけ凊理build 関数の呌び出し回数 + = n 回し、 そのたびに inorder_index[root_val] を + O(1) で取埗できるため、合蚈 + O(n) になりたす。 前凊理の dict 構築も + O(n)党芁玠を1回ず぀登録のため、 党䜓ずしお + O(n) + O(n) = O(n) です。 +

+
+
+ + +
+

+ 📖 甚語集 +

+

+ このペヌゞで登堎した専門甚語をたずめたした。分からない蚀葉が出おきたずきに参照しおください。 +

+
+
+ + ▶ O(n)・蚈算量蚘法Big-O 蚘法 + +
+ アルゎリズムの「速さ」や「メモリ䜿甚量」を入力サむズ n に察しお衚す蚘法。O(n) + は「入力が2倍になるず凊理も玄2倍になる」こずを意味したす。O(n²) + は「入力が2倍になるず凊理が玄4倍になる」ため遅く、O(1) + は「どんな入力でも䞀定」のため最速です。 +
+
+
+ + ▶ dictハッシュテヌブル・ハッシュマップ + +
+ キヌから倀を平均 O(1) で取り出せる Python + の組み蟌みデヌタ構造。内郚はハッシュテヌブル倀の堎所を蚈算で盎接求める仕組みです。図曞通の玢匕カヌドに䟋えるず、タむトルキヌから棚番号倀を即座に匕けるむメヌゞです。dict[key] + は平均 O(1) で動䜜したす。 +
+
+
+ + ▶ inorder䞭順探玢 + +
+ 二分朚の探玢方法のひず぀。「巊郚分朚 → ルヌト → + 右郚分朚」の順にノヌドを蚪れたす。この性質により、ルヌトが inorder + 配列のどこにあるかを調べるず、そのルヌトの巊に䜕ノヌドあるか巊郚分朚のサむズが分かりたす。これが朚の埩元のカギになりたす。 +
+
+
+ + ▶ nonlocal キヌワヌド + +
+ 内偎の関数から倖偎でも + global + ではないのスコヌプにある倉数を曞き換えるための Python キヌワヌド。Python の + int は䞍倉型immutableなので + += は新しいオブゞェクトを䜜る再代入になり、nonlocal + なしでは倖偎の倉数が曎新されないバグが起きたす。 +
+
+
+ + ▶ preorder前順探玢 + +
+ 二分朚の探玢方法のひず぀。「ルヌト → 巊郚分朚 → + 右郚分朚」の順にノヌドを蚪れたす。この性質により、preorder 配列の先頭芁玠が必ずその郚分朚のルヌト + になりたす。これが再垰の各ステップで「今のルヌトは䜕か」を決める根拠になりたす。 +
+
+
+ + ▶ 再垰recursion + +
+ 関数が自分自身を呌び出しお問題を小さな郚分問題に分解しお解く手法。朚の問題は「朚党䜓 = + ルヌト + 巊郚分朚 + + 右郚分朚」ずいう構造を持぀ため、再垰ず非垞に盞性がよいです。必ず「終了条件基底条件」が必芁で、今回は + lo > hi で終了したす。 +
+
+
+ + ▶ 再垰スタックRecursionError + +
+ 再垰呌び出しのたびに関数の状態倉数などがメモリに積み重ねられたす。Python + のデフォルトは深さ 1000 たで。本問では最悪 3000 + 段完党に偏った朚になりうるため、sys.setrecursionlimit(10_000) + で䞊限を緩和したす。 +
+
+
+ + ▶ 偏った朚Skewed Tree + +
+ すべおのノヌドが巊だけ・たたは右だけに぀ながった朚。通垞の二分朚バランス朚は高さ玄 + log₂(n) ですが、偏った朚は高さ n + になりたす。再垰の深さ朚の高さなので、偏った朚では再垰が深くなり + RecursionError のリスクがありたす。 +
+
+
+
+ +
+ LeetCode 105 · Python (CPython 3.11) · Time O(n) · Space O(n) +
+
+ + + + + + + + + + diff --git a/public/index.html b/public/index.html index aba3d4a4..819261f2 100644 --- a/public/index.html +++ b/public/index.html @@ -416,7 +416,7 @@

🧪 Algorithm Study Index

-

171 interactive lessons across 6 domains

+

172 interactive lessons across 6 domains

@@ -431,9 +431,9 @@

- + @@ -470,6 +470,7 @@

  • 🧩LeetCode 102 · Binary Tree Level Order TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/102. Binary Tree Level Order Traversal/README_react.html
  • 🧩LeetCode 103 – Binary Tree Zigzag Level Order TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/README_React.html
  • 🧩LeetCode 104 · Maximum Depth of Binary TreeAlgorithm/BinaryTree/claude sonnet 4.6 extended/104. Maximum Depth of Binary Tree/README_React.html
  • +
  • 🧩LeetCode 105 - 二分朚の埩元Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html
  • 🧩LeetCode 5: Longest Palindromic Substring - 䞭心展開法Algorithm/ExpandAroundCenter/leetcode/5. Longest Palindromic Substring/Claude/README.html
  • 🧩LeetCode 66: Plus One - 右から巊ぞの繰り䞊がり凊理Algorithm/Other/leetcode/66. Plus One/Claude Sonnet 4.5/README_react.html
  • 🧩LeetCode 67: Add Binary - 二進数加算Algorithm/TwoPointers/leetcode/67. Add Binary/Claude/README_react.html
  • @@ -503,8 +504,8 @@

  • 🧩Search in Rotated Sorted Array II - Technical AnalysisAlgorithm/BinarySearch/leetcode/81. Search in Rotated Sorted Array II/Claude/README.html
  • 🧩Set Matrix Zeroes Algorithm - Python ImplementationAlgorithm/Other/leetcode/73. Set Matrix Zeroes/Claude/README.html
  • 🧩Sort Colors Algorithm - Interactive Technical GuideAlgorithm/Dutch National Flag/leetcode/75. Sort Colors/Claude/README.html
  • -
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/54. Spiral Matrix/Claude/README.html
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/59. Spiral Matrix II/Claude/README.html
  • +
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/54. Spiral Matrix/Claude/README.html
  • 🧩Subsets II - 反埩的拡匵法による重耇排陀 | アルゎリズム解説Algorithm/Other/leetcode/90. Subsets II/Claude/README.html
  • 🧩Two-Pointer Algorithm: Remove Duplicates from Sorted Array IIAlgorithm/TwoPointers/leetcode/80. Remove Duplicates from Sorted Array II/Claude/README.html
  • 🧩TypeScript Binary Search Performance AnalysisAlgorithm/BinarySearch/leetcode/34. Find First and Last Position of Element in Sorted Array/READEME-typescript.html
  • @@ -648,6 +649,7 @@

  • 🧩LeetCode 102 · Binary Tree Level Order TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/102. Binary Tree Level Order Traversal/README_react.html
  • 🧩LeetCode 103 – Binary Tree Zigzag Level Order TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/README_React.html
  • 🧩LeetCode 104 · Maximum Depth of Binary TreeAlgorithm/BinaryTree/claude sonnet 4.6 extended/104. Maximum Depth of Binary Tree/README_React.html
  • +
  • 🧩LeetCode 105 - 二分朚の埩元Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html
  • 🧩LeetCode 5: Longest Palindromic Substring - 䞭心展開法Algorithm/ExpandAroundCenter/leetcode/5. Longest Palindromic Substring/Claude/README.html
  • 🧩LeetCode 66: Plus One - 右から巊ぞの繰り䞊がり凊理Algorithm/Other/leetcode/66. Plus One/Claude Sonnet 4.5/README_react.html
  • 🧩LeetCode 67: Add Binary - 二進数加算Algorithm/TwoPointers/leetcode/67. Add Binary/Claude/README_react.html
  • @@ -681,8 +683,8 @@

  • 🧩Search in Rotated Sorted Array II - Technical AnalysisAlgorithm/BinarySearch/leetcode/81. Search in Rotated Sorted Array II/Claude/README.html
  • 🧩Set Matrix Zeroes Algorithm - Python ImplementationAlgorithm/Other/leetcode/73. Set Matrix Zeroes/Claude/README.html
  • 🧩Sort Colors Algorithm - Interactive Technical GuideAlgorithm/Dutch National Flag/leetcode/75. Sort Colors/Claude/README.html
  • -
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/54. Spiral Matrix/Claude/README.html
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/59. Spiral Matrix II/Claude/README.html
  • +
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/54. Spiral Matrix/Claude/README.html
  • 🧩Subsets II - 反埩的拡匵法による重耇排陀 | アルゎリズム解説Algorithm/Other/leetcode/90. Subsets II/Claude/README.html
  • 🧩Two-Pointer Algorithm: Remove Duplicates from Sorted Array IIAlgorithm/TwoPointers/leetcode/80. Remove Duplicates from Sorted Array II/Claude/README.html
  • 🧩TypeScript Binary Search Performance AnalysisAlgorithm/BinarySearch/leetcode/34. Find First and Last Position of Element in Sorted Array/READEME-typescript.html
  • @@ -825,7 +827,7 @@

    🧪 - Generated on 2026-04-13 + Generated on 2026-04-21
    - - - - - - - - - - - -
    - - - - -
    -

    - アルゎリズム抂芁 -

    -
    -

    💡 この問題を䞀蚀で蚀うず

    -

    - preorder前順配列の先頭 = ルヌト - ずいう性質ず、 - inorder䞭順配列䞊のルヌト䜍眮 = 巊右の境界線 - ずいう性質を組み合わせお、 - 元の二分朚をノヌドのクラスむンスタンスずしお再垰的に埩元する問題です。 -

    -
    -
    -

    - ⚠ なぜ単玔な方法では解けないのか -

    -
      -
    • - preorder だけではルヌトは分かっおも巊右の分割点が特定できない耇数の朚が候補になる -
    • -
    • - inorder だけではルヌトがどれかを特定できない -
    • -
    • - 2぀を組み合わせるこずで「ルヌトの巊に䜕ノヌドあるか」が確定し、はじめお䞀意に埩元できる -
    • -
    -
    -
    -
    -
    O(n)
    -
    時間蚈算量
    -
    -
    -
    O(n)
    -
    空間蚈算量
    -
    -
    -
    1 ≀ n ≀ 3000
    -
    制玄
    -
    -
    -
    dict + 再垰
    -
    手法
    -
    -
    -
    -
    -

    // 入出力䟋 1

    -

    - preorder = [3, 9, 20, 15, 7] -

    -

    - inorder = [9, 3, 15, 20, 7] -

    -

    - ↑ inorder の「3」の巊巊郚分朚, 右右郚分朚 -

    -

    output = [3,9,20,null,null,15,7] ✅

    -
    - 埩元された朚
       3
      / \
      9  20
        / - \
       15  7
    -
    -
    -
    -

    // 入出力䟋 2

    -

    - preorder = [-1] -

    -

    - inorder = [-1] -

    -

    - ↑ 芁玠が1぀だけ → 単玔なルヌトのみの朚 -

    -

    output = [-1] ✅

    -
    - 🔑 アルゎリズムのカギpreorderの先頭が垞にルヌト。inorderのルヌト䜍眮で巊右を分ける。 -
    -
    + + + + LeetCode 105 – Construct Binary Tree from Preorder and Inorder Traversal + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + +
    +

    アルゎリズム抂芁

    + + +
    +

    💡 この問題を䞀蚀で蚀うず

    +

    「前順探玢preorderず䞭順探玢inorderずいう2皮類の配列をもずに、それを生成した元の二分朚を Python のノヌドオブゞェクトずしお再構築する問題」です。
    + preorder の先頭は必ずルヌトになり、inorder でのルヌト䜍眮が巊右の分割点を教えおくれたす。この2぀の性質を組み合わせるこずで朚を䞀意に埩元できたす。

    +
    + + +
    +

    ⚠ なぜ単玔な方法では解けないのか

    +
      +
    • 片方の配列だけでは朚が䞀意に決たらない䟋えば preorder [1,2,3] に察しお耇数の異なる二分朚が存圚したす。巊右どちらの子かが䞍明なためです。
    • +
    • 毎回 list.index() を䜿うず O(n²)n 個のノヌドそれぞれで線圢探玢するず合蚈 O(n²) になり n=3000 では玄450䞇回の比范が発生したす。dict の前凊理O(n)が䞍可欠です。
    • +
    • カヌ゜ル倉数の共有が難しいpreorder の消費䜍眮を再垰呌び出し間で正確に共有するために nonlocal の理解が必芁です。
    • +
    +
    + + +
    +
    +
    O(n)
    +
    時間蚈算量
    +
    +
    +
    O(n)
    +
    空間蚈算量
    +
    +
    +
    再垰 + dict
    +
    アルゎリズム
    +
    +
    +
    n ≀ 3000
    +
    制玄
    +
    +
    + + +
    +
    +

    📥 入力䟋 1

    +
    preorder = [3, 9, 20, 15, 7]
    +inorder  = [9, 3, 15, 20,  7]
    +

    → [3,9,20,null,null,15,7]
    + preorder先頭の3がルヌト。inorderでルヌト3の巊は[9]、右は[15,20,7]ず分かる。

    +
    +
    +

    📥 入力䟋 2

    +
    preorder = [-1]
    +inorder  = [-1]
    +

    → TreeNode(-1)
    + ノヌドが1぀だけ。巊右の子ずもNone。

    +
    +
    + + +
    +

    🔑 2぀の配列が持぀情報

    +
    +
    +
    preorder = [3, 9, 20, 15, 7]
    +
    ↑先頭 = 必ずルヌト
    「ルヌト→巊→右」の順に䞊ぶ
    -
    - - -
    -

    - ステップバむステップ解説 -

    -

    - 各ステップをクリックしお詳现を確認したしょう。▶ Play で自動再生もできたす。 -

    -
    -
    - - -
    -

    - Python 実装 -

    -
    -

    - 📋 このコヌドの構造先に党䜓像を把握しよう -

    -
      -
    1. 入力怜蚌型チェック・長さ䞍䞀臎・空リストを早期怜出
    2. -
    3. 前凊理inorder の「倀 → むンデックス」を dict 内包衚蚘で O(n) 構築
    4. -
    5. - preorder カヌ゜ル倉数を初期化し、nonlocal - で再垰間共有の準備 -
    6. -
    7. - 再垰関数 build(lo, hi)終了刀定 → ルヌト取埗 → - 分割点蚈算 → 巊右の再垰 -
    8. -
    +
    +
    inorder = [9, 3, 15, 20, 7]
    +
    ルヌト「3」の䜍眮が境界線
    å·Š[9] → ルヌト3 → 右[15,20,7]
    +
    +
    +
    + + +
    +

    ステップバむステップ解説

    +
    +
    + + +
    +

    Python 実装

    + + +
    +

    📋 このコヌドの構造先に党䜓像を把握しよう

    +
      +
    1. sys.setrecursionlimit最悪3000段の再垰に備えお䞊限を緩和する
    2. +
    3. 入力怜蚌型チェック・長さ䞍䞀臎・空リストを早期怜出する
    4. +
    5. 前凊理inorder の「倀→むンデックス」を dict 内包衚蚘で O(n) 構築する
    6. +
    7. 再垰関数 build(lo, hi)preorder カヌ゜ルを進めながら巊→右の順で郚分朚を再垰構築しお返す
    8. +
    +
    -
    import sys
    +    
    import sys
     from typing import Optional
     
    -# 再垰深床の䞊限を緩和デフォルト1000 → 偏った朚で3000段になりうる
    -sys.setrecursionlimit(10_000)
    +sys.setrecursionlimit(10_000)  # 偏った朚(n=3000)の深い再垰に備えお䞊限を緩和
    +
     
    -# Provide a lightweight TreeNode fallback for environments that do not supply it.
     class TreeNode:
         __slots__ = ("val", "left", "right")
    -    def __init__(
    -        self,
    -        val: int = 0,
    -        left: Optional["TreeNode"] = None,
    -        right: Optional["TreeNode"] = None,
    -    ) -> None:
    -        self.val = val
    -        self.left = left
    +    def __init__(self, val=0, left=None, right=None):
    +        self.val   = val
    +        self.left  = left
             self.right = right
     
    +
     class Solution:
         def buildTree(
             self,
             preorder: list[int],
    -        inorder: list[int],
    +        inorder:  list[int],
         ) -> Optional[TreeNode]:
    -        # ① 型チェック
    +        """
    +        preorder前順ず inorder䞭順から二分朚を埩元する。
    +        Time:  O(n) - 各ノヌドをちょうど1回凊理
    +        Space: O(n) - dict(n ゚ントリ) + 再垰スタック(高さ h)
    +        """
    +        # ① 型チェック: list 以倖が枡された堎合に分かりやすい゚ラヌを出す
             if not isinstance(preorder, list) or not isinstance(inorder, list):
                 raise TypeError("Both preorder and inorder must be lists")
     
    -        # ② 長さ䞍䞀臎チェック
    +        # ② 長さ䞍䞀臎チェック: 同じ朚でなければ埩元䞍可
             if len(preorder) != len(inorder):
                 raise ValueError(
                     f"Length mismatch: preorder={len(preorder)}, inorder={len(inorder)}"
                 )
     
    -        # ③ 空リストチェック
    +        # ③ 空リストチェック: ノヌド0個 → Noneを返す
             if not preorder:
                 return None
     
    -        # ④ 前凊理inorder の「倀 → むンデックス」を O(n) で dict 構築
    -        #    list.index() は毎回 O(n) → 合蚈 O(n²) になるため dict を䜿う
    +        n = len(inorder)
    +
    +        # ④ 前凊理: inorder の「倀→むンデックス」を dict 内包衚蚘で O(n) 構築
    +        #    ★毎回 list.index() を䜿うず党䜓 O(n²) → dict なら O(1) ルックアップ
             inorder_index: dict[int, int] = {val: i for i, val in enumerate(inorder)}
     
    -        # â‘€ preorder を先頭から消費するカヌ゜ルを初期化
    +        # â‘€ preorder を先頭から消費するカヌ゜ル
    +        #    int はむミュヌタブル(倉曎䞍可)なので nonlocal で倖偎倉数を共有する
             preorder_idx: int = 0
     
             def build(lo: int, hi: int) -> Optional[TreeNode]:
    -            nonlocal preorder_idx  # 倖偎のカヌ゜ルを曞き換えるこずをPythonに宣蚀
    +            """inorder の [lo, hi] 範囲に察応する郚分朚を再垰構築する"""
    +            nonlocal preorder_idx
     
    -            # ⑥ 再垰の終了条件範囲が空 → 郚分朚なし → None
    -            if lo > hi:
    +            # ⑥ 再垰の終了条件: 範囲が空(lo > hi) → 郚分朚なし
    +            if lo > hi:
                     return None
     
    -            # ⑩ preorder の珟圚䜍眮がこの郚分朚のルヌト倀
    +            # ⑩ preorder の珟圚䜍眮 = この郚分朚のルヌト倀
    +            #    preorder は「ルヌト→巊→右」順なので呌ばれた時点の先頭が必ずルヌト
                 root_val: int = preorder[preorder_idx]
                 preorder_idx += 1  # 次の再垰のためにカヌ゜ルを進める
     
                 # ⑧ dict でルヌトの inorder 䞊の䜍眮を O(1) で取埗
    +            #    この䜍眮(mid)が巊郚分朚ず右郚分朚の境界線になる
                 mid: int = inorder_index[root_val]
     
    -            # ⑹ TreeNode を生成し、巊右を再垰的に構築しお接続
    -            #    ★巊を先に構築する理由preorder は「ルヌト→巊→右」の順なので
    -            #      巊の再垰が終わるたで右のルヌト倀は preorder に珟れない
    +            # ⑹ ノヌドを生成し巊→右の順で再垰構築しお接続する
    +            #    ★巊を先にする理由: preorder が「ルヌト→巊→右」順のため
    +            #    巊の再垰が終わるず次のカヌ゜ル䜍眮が右郚分朚のルヌトになる
                 node = TreeNode(root_val)
    -            node.left = build(lo, mid - 1)    # 巊郚分朚midの巊偎
    -            node.right = build(mid + 1, hi)   # 右郚分朚midの右偎
    +            node.left  = build(lo,      mid - 1)  # 巊郚分朚(mid の巊偎)
    +            node.right = build(mid + 1, hi)        # 右郚分朚(mid の右偎)
                 return node
     
    -        # ⑩ inorder 党䜓0 〜 n-1を察象ずしお朚党䜓を構築
    -        return build(0, len(inorder) - 1)
    - -
    -

    - ▶ 入力䟋 [3,9,20,15,7] / [9,3,15,20,7] での動䜜トレヌス -

    -
    -前凊理: inorder_index = {9:0, 3:1, 15:2, 20:3, 7:4}
    -
    -build(0,4): root=preorder[0]=3, idx→1, mid=1, node=TreeNode(3)
    -  └─ .left  = build(0,0): root=preorder[1]=9, idx→2, mid=0, node=TreeNode(9)
    -              .left  = build(0,-1) → lo>hi → None
    -              .right = build(1, 0) → lo>hi → None
    -              ✅ return TreeNode(9)
    -  └─ .right = build(2,4): root=preorder[2]=20, idx→3, mid=3, node=TreeNode(20)
    -              .left  = build(2,2): root=preorder[3]=15, idx→4 → TreeNode(15)
    -              .right = build(4,4): root=preorder[4]=7,  idx→5 → TreeNode(7)
    -              ✅ return TreeNode(20, left=15, right=7)
    -✅ return TreeNode(3, left=9, right=TreeNode(20,...))
    + # ⑩ inorder 党䜓(0〜n-1)を察象に朚党䜓を構築しお返す + return build(0, n - 1) +
    + + +
    +

    ▶ 入力䟋 preorder=[3,9,20,15,7] / inorder=[9,3,15,20,7] での動䜜トレヌス

    +
    前凊理: inorder_index = {9:0, 3:1, 15:2, 20:3, 7:4}
    +preorder_idx = 0
    +
    +build(0, 4):
    +  root_val=3 (preorder[0]), preorder_idx→1, mid=inorder_index[3]=1
    +  node = TreeNode(3)
    +  node.left  = build(0, 0)
    +    root_val=9, preorder_idx→2, mid=0
    +    node.left  = build(0,-1) → lo>hi → None
    +    node.right = build(1, 0) → lo>hi → None
    +    ✅ return TreeNode(9)
    +  node.right = build(2, 4)
    +    root_val=20, preorder_idx→3, mid=3
    +    node.left  = build(2, 2)
    +      root_val=15, preorder_idx→4, mid=2
    +      → TreeNode(15, None, None)  ✅
    +    node.right = build(4, 4)
    +      root_val=7, preorder_idx→5, mid=4
    +      → TreeNode(7, None, None)   ✅
    +    ✅ return TreeNode(20, left=15, right=7)
    +✅ return TreeNode(3, left=9, right=20)
    +
    +最終ツリヌ:
    +        3
    +       / \
    +      9  20
    +         / \
    +        15   7
    +Output: [3,9,20,null,null,15,7]  ✅
    +
    +
    + + +
    +

    凊理フロヌチャヌト

    + + +
    +

    🗺 フロヌチャヌトの読み方

    +
    +
    + + 楕円緑 開始・終了
    -
    - - -
    -

    - 凊理フロヌチャヌト -

    - -
    -

    🗺 フロヌチャヌトの読み方

    -
    -
    - - - - 楕円緑 開始・終了 -
    -
    - - - - 四角玫 凊理ステップ -
    -
    - - - - ひし圢黄 条件分岐 -
    -
    - - - - Yes - - - No - -
    -
    +
    + + 四角青 凊理ステップ +
    +
    + + ひし圢黄 条件分岐 +
    +
    + 緑Yes + 赀No
    +
    +
    - -
    - - - - - - - - - - - - - - - - - - - - buildTree 開始 - - - - - - - preorder が空 - - - たたは長さ䞍䞀臎 - - - - - - Yes - - - - None / 䟋倖 - - - - - - No - - - - - - 前凊理: inorder_index 構築 - - - {val: i for i, val in enumerate(inorder)} - - - - - - - preorder_idx = 0 で初期化 - - - preorder を先頭から消費するカヌ゜ル - - - - - - - build(lo=0, hi=n-1) 呌び出し - - - 【再垰開始】 - - - - - - - lo > hi ? - - - 郚分朚が空 - - - - - - Yes - - - - None - - - - - - No - - - - - - root_val = preorder[preorder_idx] - - - preorder_idx += 1カヌ゜ルを進める - - - - - - - mid = inorder_index[root_val] - - - O(1) でルヌトの inorder 䞊の䜍眮を取埗 - - - - - - - node = TreeNode(root_val) - - - node.left = build(lo, mid-1) ← 巊郚分朚 - - - node.right = build(mid+1, hi) ← 右郚分朚 - - - - - - 再垰呌び出し - - - - - - - - node を返す - - - 芪ノヌドの left / right に接続される - - - - - - - 埩元完了 🎉 - - + +
    + + + + + + + + + + + + + buildTree 開始 + + + + + + + ① 型チェック + isinstance(preorder, list) and isinstance(inorder, list) + + + + + + + 型は正しい + + + + No + + TypeError + + + + Yes + + + + ② 長さチェック + len(preorder) == len(inorder) + + + + + + + 同じ長さ + + + + No + + ValueError + + + + Yes + + + + preorder が空 + + + + Yes + + None + + + + No + + + + ③ 前凊理: inorder_dict 構築 [O(n)] + {val: i for i, val in enumerate(inorder)} + + + + + + + ④ preorder_idx = 0 カヌ゜ル初期化 + build(0, n-1) 呌び出し + + + + + + + ─── 再垰 build(lo, hi) ─── + + + + + + lo > hi ? + 空の郚分朚 + + + + Yes + + None + + + + No + + + + â‘€ ルヌト倀を取埗しカヌ゜ルを進める + root_val = preorder[idx]; idx += 1 + + + + + + + ⑥ inorder_dict でルヌト䜍眮を O(1) 取埗 + mid = inorder_dict[root_val] + + + + + + + ⑩ node = TreeNode(root_val) 生成 + node.left = build(lo, mid-1) + + + + + + + ⑧ 右郚分朚を再垰構築しお接続 + node.right = build(mid+1, hi) + + + + + + + ⑹ return node + 再垰が終わるず最終的にルヌトが返る + + + + + + + 完成した朚のルヌトを返す ✅ + + +
    + + +
    +

    🔎 入力䟋 preorder=[3,9,20,15,7] / inorder=[9,3,15,20,7] でのフロヌ远跡

    +
      +
    1. 「buildTree 開始」→ 䞡方 list ✅ 長さ5=5 ✅ 空でない ✅
    2. +
    3. 「前凊理」→ {9:0,3:1,15:2,20:3,7:4} を O(n) で構築
    4. +
    5. 「build(0,4)」→ root_val=3, mid=1, TreeNode(3) 生成
    6. +
    7. 「build(0,0)」→ root_val=9, mid=0, TreeNode(9) → 巊右None → ✅
    8. +
    9. 「build(2,4)」→ root_val=20, mid=3, TreeNode(20)
    10. +
    11. 「build(2,2)」→ TreeNode(15)、「build(4,4)」→ TreeNode(7) → ✅
    12. +
    13. 党再垰が完了 → ルヌト TreeNode(3) を返す ✅
    14. +
    +
    + +

    + フロヌの説明
    + 入口の怜蚌①②③で゚ラヌを早期発芋し、dict 前凊理③で O(n²) を O(n) に改善したす。再垰 build(lo,hi) では終了条件 lo>hi を確認した埌、preorder カヌ゜ルからルヌトを取埗⑀し、dict でルヌトの inorder 䜍眮を特定⑥しお巊→右の順に再垰呌び出しを行いたす⑊⑧。各再垰は必ず凊理察象範囲が瞮小するため有限回で終了したす。 +

    + + + +
    +

    蚈算量分析

    + + +
    +

    📖 Big-O 蚘法の読み方

    +
    +
    +
    O(1)
    +
    垞に䞀定
    䟋: dict のルックアップ
    +
    +
    +
    O(n)
    +
    入力に比䟋
    䟋: リストを1回走査
    +
    +
    O(n log n)
    +
    n よりやや倚い
    䟋: ゜ヌトアルゎリズム
    +
    +
    +
    O(n²)
    +
    入力の2乗
    䟋: 二重ルヌプ総圓たり
    +
    +
    +
    + + +

    ⏱ 時間蚈算量

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    凊理蚈算量理由
    inorder_dict 構築O(n)党芁玠を1回ず぀登録
    build 再垰呌び出し合蚈O(n)各ノヌドをちょうど1回だけ凊理
    inorder_dict[val] 1回あたりO(1)dict の平均ルックアップコスト
    合蚈O(n)–
    +
    + + +

    💟 空間蚈算量

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    䜿甚メモリ蚈算量理由
    inorder_dictO(n)n 個のキヌ・倀ペアを保持
    再垰スタックO(h)h=朚の高さ。バランス朚 O(log n)、偏り朚 O(n)
    生成ノヌド出力O(n)埩元した朚党䜓のノヌド数
    合蚈O(n)–
    +
    + + +

    ⚖ アプロヌチ比范

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    アプロヌチ時間空間備考
    ★ dict前凊理 + 再垰今回採甚O(n)O(n)最速・コヌド明瞭
    list.index() + 再垰O(n²)O(n)n=3000 で玄450䞇回比范、TLE リスク
    反埩スタック+ dictO(n)O(n)同速だが実装が耇雑
    +
    -
    -

    - 🔎 入力䟋 [3,9,20,15,7] / [9,3,15,20,7] でのフロヌ远跡 -

    -
      -
    1. 空チェック → 芁玠5個, 䞀臎 → 続行
    2. -
    3. 前凊理 → {9:0, 3:1, 15:2, 20:3, 7:4} を構築
    4. -
    5. build(0,4)root=3, mid=1 → node=TreeNode(3)
    6. -
    7. - 巊再垰 build(0,0)root=9, mid=0 → TreeNode(9), - 巊右ずもNone -
    8. -
    9. - 右再垰 build(2,4)root=20, mid=3 → さらに巊右を再垰 -
    10. -
    11. - 党ノヌドが接続され - [3,9,20,null,null,15,7] が返る -
    12. -
    + +
    +

    🔍 なぜ O(n) になるのか

    +

    + ポむント1dict の前凊理は党芁玠を1回走査するだけなので O(n)。
    + ポむント2再垰関数 build は各ノヌドに察しお「1回だけ」呌ばれたす。preorder カヌ゜ルは単調増加0→n-1で、各倀を重耇なく消費するからです。
    + ポむント3build の䞭で行う inorder_dict[val] は平均 O(1) なので、合蚈 n × O(1) = O(n)。
    + たずめるず O(n) + O(n) = O(n) ずなりたす。 +

    +
    +
    + + +
    +

    📖 甚語集

    +

    このペヌゞで登堎した専門甚語をたずめたした。分からない蚀葉が出おきたずき参照しおください。

    +
    + +
    + + ▶ inorder䞭順探玢 + +
    + 二分朚を「巊郚分朚 → ルヌト → 右郚分朚」の順に蚪れる探玢方法。配列䞭のルヌトの䜍眮が巊右の境界線になるため、preorder ず組み合わせるず朚を䞀意に埩元できたす。
    -
    - - -
    -

    - 蚈算量分析 -

    -
    -

    - 📖 Big-O 蚘法の読み方入力サむズ n が倧きくなるに぀れお凊理時間がどう増えるかの目安 -

    -
    -
    -
    O(1)
    -
    - 垞に䞀定
    䟋dict の盎接匕き -
    -
    -
    -
    O(n)
    -
    - 入力に比䟋
    䟋リストを1回走査 -
    -
    -
    -
    O(n log n)
    -
    - nよりやや倚い
    䟋゜ヌトアルゎリズム -
    -
    -
    -
    O(n²)
    -
    - 入力の2乗
    䟋二重ルヌプ総圓たり -
    -
    -
    + + +
    + + ▶ O(n²)オヌダヌn二乗 + +
    + 入力サむズが2倍になるず凊理時間が玄4倍になるこずを瀺す蚈算量蚘法。二重ルヌプや毎回の線圢探玢に倚く芋られたす。本問で list.index() を䜿い続けるず この蚈算量になりたす。
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - アプロヌチ - - 時間蚈算量 - - 空間蚈算量 - - 備考 -
    - ★ dict 前凊理 + 再垰採甚 - - O(n) - - O(n) - - 最速・コヌド明瞭 -
    - list.index() + 再垰 - - O(n²) - - O(n) - - n=3000でTLEリスク -
    - 反埩スタック+ dict - - O(n) - - O(n) - - 同速だが実装耇雑 -
    +
    + +
    + + ▶ dictハッシュマップ + +
    + キヌから倀を平均 O(1) で取り出せる Python の組み蟌みデヌタ構造。内郚はハッシュテヌブルキヌのハッシュ倀から栌玍堎所を盎接蚈算する仕組みです。図曞通の玢匕カヌドタむトル→棚番号に䟋えられたす。
    -
    -

    🔍 なぜ O(n) になるのか

    -

    - 各ノヌドをちょうど1回だけ凊理build 関数の呌び出し回数 - = n 回し、 そのたびに inorder_index[root_val] を - O(1) で取埗できるため、合蚈 - O(n) になりたす。 前凊理の dict 構築も - O(n)党芁玠を1回ず぀登録のため、 党䜓ずしお - O(n) + O(n) = O(n) です。 -

    +
    + +
    + + ▶ nonlocalノンロヌカル宣蚀 + +
    + 内偎の関数から倖偎スコヌプにある倉数を曞き換えるための Python キヌワヌド。globalモゞュヌル倉数ずは異なり、盎近の倖偎スコヌプのみが察象。これがないず += が新しいロヌカル倉数ぞの代入ずしお扱われ、倖偎が曎新されないバグが起きたす。
    -
    - - -
    -

    - 📖 甚語集 -

    -

    - このペヌゞで登堎した専門甚語をたずめたした。分からない蚀葉が出おきたずきに参照しおください。 -

    -
    -
    - - ▶ O(n)・蚈算量蚘法Big-O 蚘法 - -
    - アルゎリズムの「速さ」や「メモリ䜿甚量」を入力サむズ n に察しお衚す蚘法。O(n) - は「入力が2倍になるず凊理も玄2倍になる」こずを意味したす。O(n²) - は「入力が2倍になるず凊理が玄4倍になる」ため遅く、O(1) - は「どんな入力でも䞀定」のため最速です。 -
    -
    -
    - - ▶ dictハッシュテヌブル・ハッシュマップ - -
    - キヌから倀を平均 O(1) で取り出せる Python - の組み蟌みデヌタ構造。内郚はハッシュテヌブル倀の堎所を蚈算で盎接求める仕組みです。図曞通の玢匕カヌドに䟋えるず、タむトルキヌから棚番号倀を即座に匕けるむメヌゞです。dict[key] - は平均 O(1) で動䜜したす。 -
    -
    -
    - - ▶ inorder䞭順探玢 - -
    - 二分朚の探玢方法のひず぀。「巊郚分朚 → ルヌト → - 右郚分朚」の順にノヌドを蚪れたす。この性質により、ルヌトが inorder - 配列のどこにあるかを調べるず、そのルヌトの巊に䜕ノヌドあるか巊郚分朚のサむズが分かりたす。これが朚の埩元のカギになりたす。 -
    -
    -
    - - ▶ nonlocal キヌワヌド - -
    - 内偎の関数から倖偎でも - global - ではないのスコヌプにある倉数を曞き換えるための Python キヌワヌド。Python の - int は䞍倉型immutableなので - += は新しいオブゞェクトを䜜る再代入になり、nonlocal - なしでは倖偎の倉数が曎新されないバグが起きたす。 -
    -
    -
    - - ▶ preorder前順探玢 - -
    - 二分朚の探玢方法のひず぀。「ルヌト → 巊郚分朚 → - 右郚分朚」の順にノヌドを蚪れたす。この性質により、preorder 配列の先頭芁玠が必ずその郚分朚のルヌト - になりたす。これが再垰の各ステップで「今のルヌトは䜕か」を決める根拠になりたす。 -
    -
    -
    - - ▶ 再垰recursion - -
    - 関数が自分自身を呌び出しお問題を小さな郚分問題に分解しお解く手法。朚の問題は「朚党䜓 = - ルヌト + 巊郚分朚 + - 右郚分朚」ずいう構造を持぀ため、再垰ず非垞に盞性がよいです。必ず「終了条件基底条件」が必芁で、今回は - lo > hi で終了したす。 -
    -
    -
    - - ▶ 再垰スタックRecursionError - -
    - 再垰呌び出しのたびに関数の状態倉数などがメモリに積み重ねられたす。Python - のデフォルトは深さ 1000 たで。本問では最悪 3000 - 段完党に偏った朚になりうるため、sys.setrecursionlimit(10_000) - で䞊限を緩和したす。 -
    -
    -
    - - ▶ 偏った朚Skewed Tree - -
    - すべおのノヌドが巊だけ・たたは右だけに぀ながった朚。通垞の二分朚バランス朚は高さ玄 - log₂(n) ですが、偏った朚は高さ n - になりたす。再垰の深さ朚の高さなので、偏った朚では再垰が深くなり - RecursionError のリスクがありたす。 -
    -
    + + +
    + + ▶ preorder前順探玢 + +
    + 二分朚を「ルヌト → 巊郚分朚 → 右郚分朚」の順に蚪れる探玢方法。配列の先頭芁玠が必ずルヌトになるずいう性質がありたす。 +
    +
    + +
    + + ▶ RecursionError再垰深床゚ラヌ + +
    + Python の再垰深床制限デフォルト1000回を超えたずきに発生する゚ラヌ。完党に偏った朚n=3000では深さ3000の再垰が起きるため、sys.setrecursionlimit(10_000) で䞊限を緩和する必芁がありたす。 +
    +
    + +
    + + ▶ 再垰Recursion + +
    + 関数が自分自身を呌び出しお問題を小さな郚分問題に分解しお解く手法。ロシア人圢マトリョヌシカの入れ子構造に䌌おおり、必ず「これ以䞊小さくできない終了条件」が必芁です。
    -
    + + +
    + + ▶ 䞍倉条件Invariant + +
    + アルゎリズムが正しく動䜜するために、凊理䞭ずっず成り立ち続けるべき条件のこず。本問では「preorder[preorder_idx] は珟圚凊理䞭の郚分朚のルヌト倀である」ずいう条件が䞍倉条件です。 +
    +
    + +
    + + ▶ 偏った朚Skewed Tree + +
    + すべおのノヌドが巊だけ・たたは右だけに぀ながった、䞀盎線の朚。再垰深床が nノヌド数ず等しくなるため最悪ケヌスずなりたす。 +
    +
    -
    - LeetCode 105 · Python (CPython 3.11) · Time O(n) · Space O(n) -
    - - - - - - - - - + )} + + {/* 操䜜ボタン */} +
    + + + + +
    + + {activeStep === stepsData.length && ( +
    + 🎉 党ステップ完了䞋の「コヌド」セクションで実際の実装を確認しおみたしょう。 +
    + )} +

    +

    + ); +} + +ReactDOM.createRoot(document.getElementById("steps-root")).render(); + + + + diff --git a/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html b/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html index 9cb4695f..80e46fa6 100644 --- a/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html +++ b/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html @@ -1,2086 +1,1081 @@ - + - - - - LeetCode 105 - 二分朚の埩元 - - - - - - - - - - - - -
    - - - - -
    -

    - アルゎリズム抂芁 -

    -
    -

    💡 この問題を䞀蚀で蚀うず

    -

    - preorder前順配列の先頭 = ルヌト - ずいう性質ず、 - inorder䞭順配列䞊のルヌト䜍眮 = 巊右の境界線 - ずいう性質を組み合わせお、 - 元の二分朚をノヌドのクラスむンスタンスずしお再垰的に埩元する問題です。 -

    -
    -
    -

    - ⚠ なぜ単玔な方法では解けないのか -

    -
      -
    • - preorder だけではルヌトは分かっおも巊右の分割点が特定できない耇数の朚が候補になる -
    • -
    • - inorder だけではルヌトがどれかを特定できない -
    • -
    • - 2぀を組み合わせるこずで「ルヌトの巊に䜕ノヌドあるか」が確定し、はじめお䞀意に埩元できる -
    • -
    -
    -
    -
    -
    O(n)
    -
    時間蚈算量
    -
    -
    -
    O(n)
    -
    空間蚈算量
    -
    -
    -
    1 ≀ n ≀ 3000
    -
    制玄
    -
    -
    -
    dict + 再垰
    -
    手法
    -
    -
    -
    -
    -

    // 入出力䟋 1

    -

    - preorder = [3, 9, 20, 15, 7] -

    -

    - inorder = [9, 3, 15, 20, 7] -

    -

    - ↑ inorder の「3」の巊巊郚分朚, 右右郚分朚 -

    -

    output = [3,9,20,null,null,15,7] ✅

    -
    - 埩元された朚
       3
      / \
      9  20
        / - \
       15  7
    -
    -
    -
    -

    // 入出力䟋 2

    -

    - preorder = [-1] -

    -

    - inorder = [-1] -

    -

    - ↑ 芁玠が1぀だけ → 単玔なルヌトのみの朚 -

    -

    output = [-1] ✅

    -
    - 🔑 アルゎリズムのカギpreorderの先頭が垞にルヌト。inorderのルヌト䜍眮で巊右を分ける。 -
    -
    + + + + LeetCode 105 – Construct Binary Tree from Preorder and Inorder Traversal + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + +
    +

    アルゎリズム抂芁

    + + +
    +

    💡 この問題を䞀蚀で蚀うず

    +

    「前順探玢preorderず䞭順探玢inorderずいう2皮類の配列をもずに、それを生成した元の二分朚を Python のノヌドオブゞェクトずしお再構築する問題」です。
    + preorder の先頭は必ずルヌトになり、inorder でのルヌト䜍眮が巊右の分割点を教えおくれたす。この2぀の性質を組み合わせるこずで朚を䞀意に埩元できたす。

    +
    + + +
    +

    ⚠ なぜ単玔な方法では解けないのか

    +
      +
    • 片方の配列だけでは朚が䞀意に決たらない䟋えば preorder [1,2,3] に察しお耇数の異なる二分朚が存圚したす。巊右どちらの子かが䞍明なためです。
    • +
    • 毎回 list.index() を䜿うず O(n²)n 個のノヌドそれぞれで線圢探玢するず合蚈 O(n²) になり n=3000 では玄450䞇回の比范が発生したす。dict の前凊理O(n)が䞍可欠です。
    • +
    • カヌ゜ル倉数の共有が難しいpreorder の消費䜍眮を再垰呌び出し間で正確に共有するために nonlocal の理解が必芁です。
    • +
    +
    + + +
    +
    +
    O(n)
    +
    時間蚈算量
    +
    +
    +
    O(n)
    +
    空間蚈算量
    +
    +
    +
    再垰 + dict
    +
    アルゎリズム
    +
    +
    +
    n ≀ 3000
    +
    制玄
    +
    +
    + + +
    +
    +

    📥 入力䟋 1

    +
    preorder = [3, 9, 20, 15, 7]
    +inorder  = [9, 3, 15, 20,  7]
    +

    → [3,9,20,null,null,15,7]
    + preorder先頭の3がルヌト。inorderでルヌト3の巊は[9]、右は[15,20,7]ず分かる。

    +
    +
    +

    📥 入力䟋 2

    +
    preorder = [-1]
    +inorder  = [-1]
    +

    → TreeNode(-1)
    + ノヌドが1぀だけ。巊右の子ずもNone。

    +
    +
    + + +
    +

    🔑 2぀の配列が持぀情報

    +
    +
    +
    preorder = [3, 9, 20, 15, 7]
    +
    ↑先頭 = 必ずルヌト
    「ルヌト→巊→右」の順に䞊ぶ
    -
    - - -
    -

    - ステップバむステップ解説 -

    -

    - 各ステップをクリックしお詳现を確認したしょう。▶ Play で自動再生もできたす。 -

    -
    -
    - - -
    -

    - Python 実装 -

    -
    -

    - 📋 このコヌドの構造先に党䜓像を把握しよう -

    -
      -
    1. 入力怜蚌型チェック・長さ䞍䞀臎・空リストを早期怜出
    2. -
    3. 前凊理inorder の「倀 → むンデックス」を dict 内包衚蚘で O(n) 構築
    4. -
    5. - preorder カヌ゜ル倉数を初期化し、nonlocal - で再垰間共有の準備 -
    6. -
    7. - 再垰関数 build(lo, hi)終了刀定 → ルヌト取埗 → - 分割点蚈算 → 巊右の再垰 -
    8. -
    +
    +
    inorder = [9, 3, 15, 20, 7]
    +
    ルヌト「3」の䜍眮が境界線
    å·Š[9] → ルヌト3 → 右[15,20,7]
    +
    +
    +
    + + +
    +

    ステップバむステップ解説

    +
    +
    + + +
    +

    Python 実装

    + + +
    +

    📋 このコヌドの構造先に党䜓像を把握しよう

    +
      +
    1. sys.setrecursionlimit最悪3000段の再垰に備えお䞊限を緩和する
    2. +
    3. 入力怜蚌型チェック・長さ䞍䞀臎・空リストを早期怜出する
    4. +
    5. 前凊理inorder の「倀→むンデックス」を dict 内包衚蚘で O(n) 構築する
    6. +
    7. 再垰関数 build(lo, hi)preorder カヌ゜ルを進めながら巊→右の順で郚分朚を再垰構築しお返す
    8. +
    +
    -
    import sys
    +    
    import sys
     from typing import Optional
     
    -# 再垰深床の䞊限を緩和デフォルト1000 → 偏った朚で3000段になりうる
    -sys.setrecursionlimit(10_000)
    +sys.setrecursionlimit(10_000)  # 偏った朚(n=3000)の深い再垰に備えお䞊限を緩和
    +
     
    -# Provide a lightweight TreeNode fallback for environments that do not supply it.
     class TreeNode:
         __slots__ = ("val", "left", "right")
    -    def __init__(
    -        self,
    -        val: int = 0,
    -        left: Optional["TreeNode"] = None,
    -        right: Optional["TreeNode"] = None,
    -    ) -> None:
    -        self.val = val
    -        self.left = left
    +    def __init__(self, val=0, left=None, right=None):
    +        self.val   = val
    +        self.left  = left
             self.right = right
     
    +
     class Solution:
         def buildTree(
             self,
             preorder: list[int],
    -        inorder: list[int],
    +        inorder:  list[int],
         ) -> Optional[TreeNode]:
    -        # ① 型チェック
    +        """
    +        preorder前順ず inorder䞭順から二分朚を埩元する。
    +        Time:  O(n) - 各ノヌドをちょうど1回凊理
    +        Space: O(n) - dict(n ゚ントリ) + 再垰スタック(高さ h)
    +        """
    +        # ① 型チェック: list 以倖が枡された堎合に分かりやすい゚ラヌを出す
             if not isinstance(preorder, list) or not isinstance(inorder, list):
                 raise TypeError("Both preorder and inorder must be lists")
     
    -        # ② 長さ䞍䞀臎チェック
    +        # ② 長さ䞍䞀臎チェック: 同じ朚でなければ埩元䞍可
             if len(preorder) != len(inorder):
                 raise ValueError(
                     f"Length mismatch: preorder={len(preorder)}, inorder={len(inorder)}"
                 )
     
    -        # ③ 空リストチェック
    +        # ③ 空リストチェック: ノヌド0個 → Noneを返す
             if not preorder:
                 return None
     
    -        # ④ 前凊理inorder の「倀 → むンデックス」を O(n) で dict 構築
    -        #    list.index() は毎回 O(n) → 合蚈 O(n²) になるため dict を䜿う
    +        n = len(inorder)
    +
    +        # ④ 前凊理: inorder の「倀→むンデックス」を dict 内包衚蚘で O(n) 構築
    +        #    ★毎回 list.index() を䜿うず党䜓 O(n²) → dict なら O(1) ルックアップ
             inorder_index: dict[int, int] = {val: i for i, val in enumerate(inorder)}
     
    -        # â‘€ preorder を先頭から消費するカヌ゜ルを初期化
    +        # â‘€ preorder を先頭から消費するカヌ゜ル
    +        #    int はむミュヌタブル(倉曎䞍可)なので nonlocal で倖偎倉数を共有する
             preorder_idx: int = 0
     
             def build(lo: int, hi: int) -> Optional[TreeNode]:
    -            nonlocal preorder_idx  # 倖偎のカヌ゜ルを曞き換えるこずをPythonに宣蚀
    +            """inorder の [lo, hi] 範囲に察応する郚分朚を再垰構築する"""
    +            nonlocal preorder_idx
     
    -            # ⑥ 再垰の終了条件範囲が空 → 郚分朚なし → None
    -            if lo > hi:
    +            # ⑥ 再垰の終了条件: 範囲が空(lo > hi) → 郚分朚なし
    +            if lo > hi:
                     return None
     
    -            # ⑩ preorder の珟圚䜍眮がこの郚分朚のルヌト倀
    +            # ⑩ preorder の珟圚䜍眮 = この郚分朚のルヌト倀
    +            #    preorder は「ルヌト→巊→右」順なので呌ばれた時点の先頭が必ずルヌト
                 root_val: int = preorder[preorder_idx]
                 preorder_idx += 1  # 次の再垰のためにカヌ゜ルを進める
     
                 # ⑧ dict でルヌトの inorder 䞊の䜍眮を O(1) で取埗
    +            #    この䜍眮(mid)が巊郚分朚ず右郚分朚の境界線になる
                 mid: int = inorder_index[root_val]
     
    -            # ⑹ TreeNode を生成し、巊右を再垰的に構築しお接続
    -            #    ★巊を先に構築する理由preorder は「ルヌト→巊→右」の順なので
    -            #      巊の再垰が終わるたで右のルヌト倀は preorder に珟れない
    +            # ⑹ ノヌドを生成し巊→右の順で再垰構築しお接続する
    +            #    ★巊を先にする理由: preorder が「ルヌト→巊→右」順のため
    +            #    巊の再垰が終わるず次のカヌ゜ル䜍眮が右郚分朚のルヌトになる
                 node = TreeNode(root_val)
    -            node.left = build(lo, mid - 1)    # 巊郚分朚midの巊偎
    -            node.right = build(mid + 1, hi)   # 右郚分朚midの右偎
    +            node.left  = build(lo,      mid - 1)  # 巊郚分朚(mid の巊偎)
    +            node.right = build(mid + 1, hi)        # 右郚分朚(mid の右偎)
                 return node
     
    -        # ⑩ inorder 党䜓0 〜 n-1を察象ずしお朚党䜓を構築
    -        return build(0, len(inorder) - 1)
    - -
    -

    - ▶ 入力䟋 [3,9,20,15,7] / [9,3,15,20,7] での動䜜トレヌス -

    -
    -前凊理: inorder_index = {9:0, 3:1, 15:2, 20:3, 7:4}
    -
    -build(0,4): root=preorder[0]=3, idx→1, mid=1, node=TreeNode(3)
    -  └─ .left  = build(0,0): root=preorder[1]=9, idx→2, mid=0, node=TreeNode(9)
    -              .left  = build(0,-1) → lo>hi → None
    -              .right = build(1, 0) → lo>hi → None
    -              ✅ return TreeNode(9)
    -  └─ .right = build(2,4): root=preorder[2]=20, idx→3, mid=3, node=TreeNode(20)
    -              .left  = build(2,2): root=preorder[3]=15, idx→4 → TreeNode(15)
    -              .right = build(4,4): root=preorder[4]=7,  idx→5 → TreeNode(7)
    -              ✅ return TreeNode(20, left=15, right=7)
    -✅ return TreeNode(3, left=9, right=TreeNode(20,...))
    + # ⑩ inorder 党䜓(0〜n-1)を察象に朚党䜓を構築しお返す + return build(0, n - 1) +
    + + +
    +

    ▶ 入力䟋 preorder=[3,9,20,15,7] / inorder=[9,3,15,20,7] での動䜜トレヌス

    +
    前凊理: inorder_index = {9:0, 3:1, 15:2, 20:3, 7:4}
    +preorder_idx = 0
    +
    +build(0, 4):
    +  root_val=3 (preorder[0]), preorder_idx→1, mid=inorder_index[3]=1
    +  node = TreeNode(3)
    +  node.left  = build(0, 0)
    +    root_val=9, preorder_idx→2, mid=0
    +    node.left  = build(0,-1) → lo>hi → None
    +    node.right = build(1, 0) → lo>hi → None
    +    ✅ return TreeNode(9)
    +  node.right = build(2, 4)
    +    root_val=20, preorder_idx→3, mid=3
    +    node.left  = build(2, 2)
    +      root_val=15, preorder_idx→4, mid=2
    +      → TreeNode(15, None, None)  ✅
    +    node.right = build(4, 4)
    +      root_val=7, preorder_idx→5, mid=4
    +      → TreeNode(7, None, None)   ✅
    +    ✅ return TreeNode(20, left=15, right=7)
    +✅ return TreeNode(3, left=9, right=20)
    +
    +最終ツリヌ:
    +        3
    +       / \
    +      9  20
    +         / \
    +        15   7
    +Output: [3,9,20,null,null,15,7]  ✅
    +
    +
    + + +
    +

    凊理フロヌチャヌト

    + + +
    +

    🗺 フロヌチャヌトの読み方

    +
    +
    + + 楕円緑 開始・終了
    -
    - - -
    -

    - 凊理フロヌチャヌト -

    - -
    -

    🗺 フロヌチャヌトの読み方

    -
    -
    - - - - 楕円緑 開始・終了 -
    -
    - - - - 四角玫 凊理ステップ -
    -
    - - - - ひし圢黄 条件分岐 -
    -
    - - - - Yes - - - No - -
    -
    +
    + + 四角青 凊理ステップ +
    +
    + + ひし圢黄 条件分岐 +
    +
    + 緑Yes + 赀No
    +
    +
    - -
    - - - - - - - - - - - - - - - - - - - - buildTree 開始 - - - - - - - preorder が空 - - - たたは長さ䞍䞀臎 - - - - - - Yes - - - - None / 䟋倖 - - - - - - No - - - - - - 前凊理: inorder_index 構築 - - - {val: i for i, val in enumerate(inorder)} - - - - - - - preorder_idx = 0 で初期化 - - - preorder を先頭から消費するカヌ゜ル - - - - - - - build(lo=0, hi=n-1) 呌び出し - - - 【再垰開始】 - - - - - - - lo > hi ? - - - 郚分朚が空 - - - - - - Yes - - - - None - - - - - - No - - - - - - root_val = preorder[preorder_idx] - - - preorder_idx += 1カヌ゜ルを進める - - - - - - - mid = inorder_index[root_val] - - - O(1) でルヌトの inorder 䞊の䜍眮を取埗 - - - - - - - node = TreeNode(root_val) - - - node.left = build(lo, mid-1) ← 巊郚分朚 - - - node.right = build(mid+1, hi) ← 右郚分朚 - - - - - - 再垰呌び出し - - - - - - - - node を返す - - - 芪ノヌドの left / right に接続される - - - - - - - 埩元完了 🎉 - - + +
    + + + + + + + + + + + + + buildTree 開始 + + + + + + + ① 型チェック + isinstance(preorder, list) and isinstance(inorder, list) + + + + + + + 型は正しい + + + + No + + TypeError + + + + Yes + + + + ② 長さチェック + len(preorder) == len(inorder) + + + + + + + 同じ長さ + + + + No + + ValueError + + + + Yes + + + + preorder が空 + + + + Yes + + None + + + + No + + + + ③ 前凊理: inorder_dict 構築 [O(n)] + {val: i for i, val in enumerate(inorder)} + + + + + + + ④ preorder_idx = 0 カヌ゜ル初期化 + build(0, n-1) 呌び出し + + + + + + + ─── 再垰 build(lo, hi) ─── + + + + + + lo > hi ? + 空の郚分朚 + + + + Yes + + None + + + + No + + + + â‘€ ルヌト倀を取埗しカヌ゜ルを進める + root_val = preorder[idx]; idx += 1 + + + + + + + ⑥ inorder_dict でルヌト䜍眮を O(1) 取埗 + mid = inorder_dict[root_val] + + + + + + + ⑩ node = TreeNode(root_val) 生成 + node.left = build(lo, mid-1) + + + + + + + ⑧ 右郚分朚を再垰構築しお接続 + node.right = build(mid+1, hi) + + + + + + + ⑹ return node + 再垰が終わるず最終的にルヌトが返る + + + + + + + 完成した朚のルヌトを返す ✅ + + +
    + + +
    +

    🔎 入力䟋 preorder=[3,9,20,15,7] / inorder=[9,3,15,20,7] でのフロヌ远跡

    +
      +
    1. 「buildTree 開始」→ 䞡方 list ✅ 長さ5=5 ✅ 空でない ✅
    2. +
    3. 「前凊理」→ {9:0,3:1,15:2,20:3,7:4} を O(n) で構築
    4. +
    5. 「build(0,4)」→ root_val=3, mid=1, TreeNode(3) 生成
    6. +
    7. 「build(0,0)」→ root_val=9, mid=0, TreeNode(9) → 巊右None → ✅
    8. +
    9. 「build(2,4)」→ root_val=20, mid=3, TreeNode(20)
    10. +
    11. 「build(2,2)」→ TreeNode(15)、「build(4,4)」→ TreeNode(7) → ✅
    12. +
    13. 党再垰が完了 → ルヌト TreeNode(3) を返す ✅
    14. +
    +
    + +

    + フロヌの説明
    + 入口の怜蚌①②③で゚ラヌを早期発芋し、dict 前凊理③で O(n²) を O(n) に改善したす。再垰 build(lo,hi) では終了条件 lo>hi を確認した埌、preorder カヌ゜ルからルヌトを取埗⑀し、dict でルヌトの inorder 䜍眮を特定⑥しお巊→右の順に再垰呌び出しを行いたす⑊⑧。各再垰は必ず凊理察象範囲が瞮小するため有限回で終了したす。 +

    + + + +
    +

    蚈算量分析

    + + +
    +

    📖 Big-O 蚘法の読み方

    +
    +
    +
    O(1)
    +
    垞に䞀定
    䟋: dict のルックアップ
    +
    +
    +
    O(n)
    +
    入力に比䟋
    䟋: リストを1回走査
    +
    +
    O(n log n)
    +
    n よりやや倚い
    䟋: ゜ヌトアルゎリズム
    +
    +
    +
    O(n²)
    +
    入力の2乗
    䟋: 二重ルヌプ総圓たり
    +
    +
    +
    + + +

    ⏱ 時間蚈算量

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    凊理蚈算量理由
    inorder_dict 構築O(n)党芁玠を1回ず぀登録
    build 再垰呌び出し合蚈O(n)各ノヌドをちょうど1回だけ凊理
    inorder_dict[val] 1回あたりO(1)dict の平均ルックアップコスト
    合蚈O(n)–
    +
    + + +

    💟 空間蚈算量

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    䜿甚メモリ蚈算量理由
    inorder_dictO(n)n 個のキヌ・倀ペアを保持
    再垰スタックO(h)h=朚の高さ。バランス朚 O(log n)、偏り朚 O(n)
    生成ノヌド出力O(n)埩元した朚党䜓のノヌド数
    合蚈O(n)–
    +
    + + +

    ⚖ アプロヌチ比范

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    アプロヌチ時間空間備考
    ★ dict前凊理 + 再垰今回採甚O(n)O(n)最速・コヌド明瞭
    list.index() + 再垰O(n²)O(n)n=3000 で玄450䞇回比范、TLE リスク
    反埩スタック+ dictO(n)O(n)同速だが実装が耇雑
    +
    -
    -

    - 🔎 入力䟋 [3,9,20,15,7] / [9,3,15,20,7] でのフロヌ远跡 -

    -
      -
    1. 空チェック → 芁玠5個, 䞀臎 → 続行
    2. -
    3. 前凊理 → {9:0, 3:1, 15:2, 20:3, 7:4} を構築
    4. -
    5. build(0,4)root=3, mid=1 → node=TreeNode(3)
    6. -
    7. - 巊再垰 build(0,0)root=9, mid=0 → TreeNode(9), - 巊右ずもNone -
    8. -
    9. - 右再垰 build(2,4)root=20, mid=3 → さらに巊右を再垰 -
    10. -
    11. - 党ノヌドが接続され - [3,9,20,null,null,15,7] が返る -
    12. -
    + +
    +

    🔍 なぜ O(n) になるのか

    +

    + ポむント1dict の前凊理は党芁玠を1回走査するだけなので O(n)。
    + ポむント2再垰関数 build は各ノヌドに察しお「1回だけ」呌ばれたす。preorder カヌ゜ルは単調増加0→n-1で、各倀を重耇なく消費するからです。
    + ポむント3build の䞭で行う inorder_dict[val] は平均 O(1) なので、合蚈 n × O(1) = O(n)。
    + たずめるず O(n) + O(n) = O(n) ずなりたす。 +

    +
    +
    + + +
    +

    📖 甚語集

    +

    このペヌゞで登堎した専門甚語をたずめたした。分からない蚀葉が出おきたずき参照しおください。

    +
    + +
    + + ▶ inorder䞭順探玢 + +
    + 二分朚を「巊郚分朚 → ルヌト → 右郚分朚」の順に蚪れる探玢方法。配列䞭のルヌトの䜍眮が巊右の境界線になるため、preorder ず組み合わせるず朚を䞀意に埩元できたす。
    -
    - - -
    -

    - 蚈算量分析 -

    -
    -

    - 📖 Big-O 蚘法の読み方入力サむズ n が倧きくなるに぀れお凊理時間がどう増えるかの目安 -

    -
    -
    -
    O(1)
    -
    - 垞に䞀定
    䟋dict の盎接匕き -
    -
    -
    -
    O(n)
    -
    - 入力に比䟋
    䟋リストを1回走査 -
    -
    -
    -
    O(n log n)
    -
    - nよりやや倚い
    䟋゜ヌトアルゎリズム -
    -
    -
    -
    O(n²)
    -
    - 入力の2乗
    䟋二重ルヌプ総圓たり -
    -
    -
    + + +
    + + ▶ O(n²)オヌダヌn二乗 + +
    + 入力サむズが2倍になるず凊理時間が玄4倍になるこずを瀺す蚈算量蚘法。二重ルヌプや毎回の線圢探玢に倚く芋られたす。本問で list.index() を䜿い続けるず この蚈算量になりたす。
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - アプロヌチ - - 時間蚈算量 - - 空間蚈算量 - - 備考 -
    - ★ dict 前凊理 + 再垰採甚 - - O(n) - - O(n) - - 最速・コヌド明瞭 -
    - list.index() + 再垰 - - O(n²) - - O(n) - - n=3000でTLEリスク -
    - 反埩スタック+ dict - - O(n) - - O(n) - - 同速だが実装耇雑 -
    +
    + +
    + + ▶ dictハッシュマップ + +
    + キヌから倀を平均 O(1) で取り出せる Python の組み蟌みデヌタ構造。内郚はハッシュテヌブルキヌのハッシュ倀から栌玍堎所を盎接蚈算する仕組みです。図曞通の玢匕カヌドタむトル→棚番号に䟋えられたす。
    -
    -

    🔍 なぜ O(n) になるのか

    -

    - 各ノヌドをちょうど1回だけ凊理build 関数の呌び出し回数 - = n 回し、 そのたびに inorder_index[root_val] を - O(1) で取埗できるため、合蚈 - O(n) になりたす。 前凊理の dict 構築も - O(n)党芁玠を1回ず぀登録のため、 党䜓ずしお - O(n) + O(n) = O(n) です。 -

    +
    + +
    + + ▶ nonlocalノンロヌカル宣蚀 + +
    + 内偎の関数から倖偎スコヌプにある倉数を曞き換えるための Python キヌワヌド。globalモゞュヌル倉数ずは異なり、盎近の倖偎スコヌプのみが察象。これがないず += が新しいロヌカル倉数ぞの代入ずしお扱われ、倖偎が曎新されないバグが起きたす。
    -
    - - -
    -

    - 📖 甚語集 -

    -

    - このペヌゞで登堎した専門甚語をたずめたした。分からない蚀葉が出おきたずきに参照しおください。 -

    -
    -
    - - ▶ O(n)・蚈算量蚘法Big-O 蚘法 - -
    - アルゎリズムの「速さ」や「メモリ䜿甚量」を入力サむズ n に察しお衚す蚘法。O(n) - は「入力が2倍になるず凊理も玄2倍になる」こずを意味したす。O(n²) - は「入力が2倍になるず凊理が玄4倍になる」ため遅く、O(1) - は「どんな入力でも䞀定」のため最速です。 -
    -
    -
    - - ▶ dictハッシュテヌブル・ハッシュマップ - -
    - キヌから倀を平均 O(1) で取り出せる Python - の組み蟌みデヌタ構造。内郚はハッシュテヌブル倀の堎所を蚈算で盎接求める仕組みです。図曞通の玢匕カヌドに䟋えるず、タむトルキヌから棚番号倀を即座に匕けるむメヌゞです。dict[key] - は平均 O(1) で動䜜したす。 -
    -
    -
    - - ▶ inorder䞭順探玢 - -
    - 二分朚の探玢方法のひず぀。「巊郚分朚 → ルヌト → - 右郚分朚」の順にノヌドを蚪れたす。この性質により、ルヌトが inorder - 配列のどこにあるかを調べるず、そのルヌトの巊に䜕ノヌドあるか巊郚分朚のサむズが分かりたす。これが朚の埩元のカギになりたす。 -
    -
    -
    - - ▶ nonlocal キヌワヌド - -
    - 内偎の関数から倖偎でも - global - ではないのスコヌプにある倉数を曞き換えるための Python キヌワヌド。Python の - int は䞍倉型immutableなので - += は新しいオブゞェクトを䜜る再代入になり、nonlocal - なしでは倖偎の倉数が曎新されないバグが起きたす。 -
    -
    -
    - - ▶ preorder前順探玢 - -
    - 二分朚の探玢方法のひず぀。「ルヌト → 巊郚分朚 → - 右郚分朚」の順にノヌドを蚪れたす。この性質により、preorder 配列の先頭芁玠が必ずその郚分朚のルヌト - になりたす。これが再垰の各ステップで「今のルヌトは䜕か」を決める根拠になりたす。 -
    -
    -
    - - ▶ 再垰recursion - -
    - 関数が自分自身を呌び出しお問題を小さな郚分問題に分解しお解く手法。朚の問題は「朚党䜓 = - ルヌト + 巊郚分朚 + - 右郚分朚」ずいう構造を持぀ため、再垰ず非垞に盞性がよいです。必ず「終了条件基底条件」が必芁で、今回は - lo > hi で終了したす。 -
    -
    -
    - - ▶ 再垰スタックRecursionError - -
    - 再垰呌び出しのたびに関数の状態倉数などがメモリに積み重ねられたす。Python - のデフォルトは深さ 1000 たで。本問では最悪 3000 - 段完党に偏った朚になりうるため、sys.setrecursionlimit(10_000) - で䞊限を緩和したす。 -
    -
    -
    - - ▶ 偏った朚Skewed Tree - -
    - すべおのノヌドが巊だけ・たたは右だけに぀ながった朚。通垞の二分朚バランス朚は高さ玄 - log₂(n) ですが、偏った朚は高さ n - になりたす。再垰の深さ朚の高さなので、偏った朚では再垰が深くなり - RecursionError のリスクがありたす。 -
    -
    + + +
    + + ▶ preorder前順探玢 + +
    + 二分朚を「ルヌト → 巊郚分朚 → 右郚分朚」の順に蚪れる探玢方法。配列の先頭芁玠が必ずルヌトになるずいう性質がありたす。 +
    +
    + +
    + + ▶ RecursionError再垰深床゚ラヌ + +
    + Python の再垰深床制限デフォルト1000回を超えたずきに発生する゚ラヌ。完党に偏った朚n=3000では深さ3000の再垰が起きるため、sys.setrecursionlimit(10_000) で䞊限を緩和する必芁がありたす。 +
    +
    + +
    + + ▶ 再垰Recursion + +
    + 関数が自分自身を呌び出しお問題を小さな郚分問題に分解しお解く手法。ロシア人圢マトリョヌシカの入れ子構造に䌌おおり、必ず「これ以䞊小さくできない終了条件」が必芁です。
    -
    + + +
    + + ▶ 䞍倉条件Invariant + +
    + アルゎリズムが正しく動䜜するために、凊理䞭ずっず成り立ち続けるべき条件のこず。本問では「preorder[preorder_idx] は珟圚凊理䞭の郚分朚のルヌト倀である」ずいう条件が䞍倉条件です。 +
    +
    + +
    + + ▶ 偏った朚Skewed Tree + +
    + すべおのノヌドが巊だけ・たたは右だけに぀ながった、䞀盎線の朚。再垰深床が nノヌド数ず等しくなるため最悪ケヌスずなりたす。 +
    +
    -
    - LeetCode 105 · Python (CPython 3.11) · Time O(n) · Space O(n) -
    - - - - - - - - - + )} + + {/* 操䜜ボタン */} +
    + + + + +
    + + {activeStep === stepsData.length && ( +
    + 🎉 党ステップ完了䞋の「コヌド」セクションで実際の実装を確認しおみたしょう。 +
    + )} + + + ); +} + +ReactDOM.createRoot(document.getElementById("steps-root")).render(); + + + + diff --git a/public/index.html b/public/index.html index 54834b51..87b38442 100644 --- a/public/index.html +++ b/public/index.html @@ -470,7 +470,7 @@

  • 🧩LeetCode 102 · Binary Tree Level Order TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/102. Binary Tree Level Order Traversal/README_react.html
  • 🧩LeetCode 103 – Binary Tree Zigzag Level Order TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/README_React.html
  • 🧩LeetCode 104 · Maximum Depth of Binary TreeAlgorithm/BinaryTree/claude sonnet 4.6 extended/104. Maximum Depth of Binary Tree/README_React.html
  • -
  • 🧩LeetCode 105 - 二分朚の埩元Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html
  • +
  • 🧩LeetCode 105 – Construct Binary Tree from Preorder and Inorder TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html
  • 🧩LeetCode 5: Longest Palindromic Substring - 䞭心展開法Algorithm/ExpandAroundCenter/leetcode/5. Longest Palindromic Substring/Claude/README.html
  • 🧩LeetCode 66: Plus One - 右から巊ぞの繰り䞊がり凊理Algorithm/Other/leetcode/66. Plus One/Claude Sonnet 4.5/README_react.html
  • 🧩LeetCode 67: Add Binary - 二進数加算Algorithm/TwoPointers/leetcode/67. Add Binary/Claude/README_react.html
  • @@ -504,8 +504,8 @@

  • 🧩Search in Rotated Sorted Array II - Technical AnalysisAlgorithm/BinarySearch/leetcode/81. Search in Rotated Sorted Array II/Claude/README.html
  • 🧩Set Matrix Zeroes Algorithm - Python ImplementationAlgorithm/Other/leetcode/73. Set Matrix Zeroes/Claude/README.html
  • 🧩Sort Colors Algorithm - Interactive Technical GuideAlgorithm/Dutch National Flag/leetcode/75. Sort Colors/Claude/README.html
  • -
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/54. Spiral Matrix/Claude/README.html
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/59. Spiral Matrix II/Claude/README.html
  • +
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/54. Spiral Matrix/Claude/README.html
  • 🧩Subsets II - 反埩的拡匵法による重耇排陀 | アルゎリズム解説Algorithm/Other/leetcode/90. Subsets II/Claude/README.html
  • 🧩Two-Pointer Algorithm: Remove Duplicates from Sorted Array IIAlgorithm/TwoPointers/leetcode/80. Remove Duplicates from Sorted Array II/Claude/README.html
  • 🧩TypeScript Binary Search Performance AnalysisAlgorithm/BinarySearch/leetcode/34. Find First and Last Position of Element in Sorted Array/READEME-typescript.html
  • @@ -649,7 +649,7 @@

  • 🧩LeetCode 102 · Binary Tree Level Order TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/102. Binary Tree Level Order Traversal/README_react.html
  • 🧩LeetCode 103 – Binary Tree Zigzag Level Order TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/README_React.html
  • 🧩LeetCode 104 · Maximum Depth of Binary TreeAlgorithm/BinaryTree/claude sonnet 4.6 extended/104. Maximum Depth of Binary Tree/README_React.html
  • -
  • 🧩LeetCode 105 - 二分朚の埩元Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html
  • +
  • 🧩LeetCode 105 – Construct Binary Tree from Preorder and Inorder TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html
  • 🧩LeetCode 5: Longest Palindromic Substring - 䞭心展開法Algorithm/ExpandAroundCenter/leetcode/5. Longest Palindromic Substring/Claude/README.html
  • 🧩LeetCode 66: Plus One - 右から巊ぞの繰り䞊がり凊理Algorithm/Other/leetcode/66. Plus One/Claude Sonnet 4.5/README_react.html
  • 🧩LeetCode 67: Add Binary - 二進数加算Algorithm/TwoPointers/leetcode/67. Add Binary/Claude/README_react.html
  • @@ -683,8 +683,8 @@

  • 🧩Search in Rotated Sorted Array II - Technical AnalysisAlgorithm/BinarySearch/leetcode/81. Search in Rotated Sorted Array II/Claude/README.html
  • 🧩Set Matrix Zeroes Algorithm - Python ImplementationAlgorithm/Other/leetcode/73. Set Matrix Zeroes/Claude/README.html
  • 🧩Sort Colors Algorithm - Interactive Technical GuideAlgorithm/Dutch National Flag/leetcode/75. Sort Colors/Claude/README.html
  • -
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/54. Spiral Matrix/Claude/README.html
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/59. Spiral Matrix II/Claude/README.html
  • +
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/54. Spiral Matrix/Claude/README.html
  • 🧩Subsets II - 反埩的拡匵法による重耇排陀 | アルゎリズム解説Algorithm/Other/leetcode/90. Subsets II/Claude/README.html
  • 🧩Two-Pointer Algorithm: Remove Duplicates from Sorted Array IIAlgorithm/TwoPointers/leetcode/80. Remove Duplicates from Sorted Array II/Claude/README.html
  • 🧩TypeScript Binary Search Performance AnalysisAlgorithm/BinarySearch/leetcode/34. Find First and Last Position of Element in Sorted Array/READEME-typescript.html
  • @@ -827,7 +827,7 @@

    🧪 - Generated on 2026-04-21 + Generated on 2026-04-22
    + + + + + + + + + + + + + + + +
    + + + + + +
    +

    アルゎリズム抂芁

    + +
    +

    + 💡 この問題を䞀蚀で蚀うず「2皮類の朚の巡回蚘録Inorder・Postorderを手がかりに、元の二分朚の圢を埩元する問題」 +

    +

    + 二分朚を「巡回する順番のルヌル」が耇数あり、Postorderの末尟芁玠は必ずその郚分朚のルヌト根になりたす。この性質ずHashMapを組み合わせるこずで、配列コピヌなしにO(n)で朚を再構築できたす。 +

    +
    + +
    +

    ⚠ なぜ単玔な方法では解けないのか

    +
      +
    • list.index() でルヌト䜍眮を毎回探すず O(n) × n回  O(n²) になりTLEになるn=3000で最倧900䞇回の操䜜
    • +
    • 配列をスラむスしおコピヌしながら再垰するず O(n²) のメモリが必芁になりMLEになる
    • +
    • Pythonのデフォルト再垰䞊限は1000。偏った朚ではn=3000段の再垰が必芁になるため sys.setrecursionlimit が必須
    • +
    +
    + + +
    +
    +
    O(n)
    +
    時間蚈算量
    +
    +
    +
    O(n)
    +
    空間蚈算量
    +
    +
    +
    HashMap+再垰
    +
    アルゎリズム
    +
    +
    +
    ≀ 3000
    +
    入力サむズ䞊限
    +
    +
    + + +
    +
    +

    入力

    +
    inorder   = [9, 3, 15, 20, 7]
    +postorder = [9, 15, 7, 20, 3]
    +
    +
    +

    出力朚の圢

    +
          3
    +     / \
    +    9   20
    +       /  \
    +      15    7
    +
    +
    +

    + なぜこれが正解か + postorderの末尟3がルヌト → inorderで3の巊が[9]巊郚分朚、右が[15,20,7]右郚分朚ず特定できる。この操䜜を再垰的に繰り返すこずで朚党䜓を埩元できる。 +

    +
    + + +
    +

    ステップバむステップ解説

    +

    ▶ Play ボタンで自動再生、Prev/Next で手動操䜜できたす。

    +
    +
    + + +
    +

    Python 実装

    + +
    +

    📋 このコヌドの構造先に党䜓像を把握しよう

    +
      +
    1. 再垰䞊限匕き䞊げ完党偏り朚でも安党に動䜜させるため sys.setrecursionlimit(10_000) を蚭定
    2. +
    3. HashMap構築idx_map = {v: i for i, v in enumerate(inorder)} で O(1) 怜玢を可胜にする
    4. +
    5. ポむンタ初期化post_idx = [len(postorder) - 1] で末尟からルヌトを消費するカヌ゜ルを蚭眮
    6. +
    7. 再垰ヘルパヌ dfs終了条件チェック → ルヌト取埗 → 右郚分朚を先に再垰 → 巊郚分朚を再垰 → ノヌド返华
    8. +
    +
    + +
    import sys
    +from typing import Optional, List
    +
    +class Solution:
    +    def buildTree(
    +        self,
    +        inorder: List[int],
    +        postorder: List[int]
    +    ) -> Optional[TreeNode]:
    +        # Python のデフォルト再垰䞊限は 1000。
    +        # 完党偏り朚では n=3000 段の再垰が必芁になるため䞊限を匕き䞊げる。
    +        sys.setrecursionlimit(10_000)
    +
    +        # dict 内包衚蚘で「倀 → inorder のむンデックス」を O(n) で1回だけ構築。
    +        # list.index() を毎回呌ぶず O(n²) になるため、事前構築で O(1) 怜玢を実珟。
    +        idx_map: dict[int, int] = {v: i for i, v in enumerate(inorder)}
    +
    +        # post_idx をリストで包む慣甚句。
    +        # 内偎関数から倖偎の int を曞き換えるには nonlocal が必芁だが、
    +        # リストに包むこずで「リストの䞭身を倉える」操䜜になり nonlocal 䞍芁になる。
    +        post_idx: List[int] = [len(postorder) - 1]
    +
    +        def dfs(left: int, right: int) -> Optional[TreeNode]:
    +            # 終了条件巊端が右端を超えた = この範囲に芁玠がない = 郚分朚なし
    +            if left > right:
    +                return None
    +
    +            # postorder の末尟から珟圚の郚分朚のルヌトを取り出す。
    +            # list のむンデックスアクセスは O(1)。カヌ゜ルを1぀前に進める。
    +            val: int = postorder[post_idx[0]]
    +            post_idx[0] -= 1
    +
    +            # ルヌトノヌドを䜜成する。
    +            node = TreeNode(val)
    +
    +            # dict から O(1) でルヌトの inorder 䞊の䜍眮を取埗する。
    +            # この䜍眮より「巊偎」が巊郚分朚、「右偎」が右郚分朚になる。
    +            mid: int = idx_map[val]
    +
    +            # ★重芁★ 右郚分朚を先に再垰する理由
    +            # postorder を末尟から逆順に消費するず「ルヌト→右→巊」の順になる。
    +            # ぀たり次の pop は「右郚分朚のルヌト」を指しおいる。
    +            # 巊を先にするず消費順序がずれお誀った朚になっおしたう。
    +            node.right = dfs(mid + 1, right)  # 右mid+1 〜 right
    +            node.left  = dfs(left, mid - 1)   # 巊left 〜 mid-1
    +
    +            return node
    +
    +        # inorder の党範囲0 〜 n-1を察象に朚を構築しお返す
    +        return dfs(0, len(inorder) - 1)
    + +
    +

    ▶ 入力䟋 inorder=[9,3,15,20,7], postorder=[9,15,7,20,3] での動䜜トレヌス

    +
    事前準備:
    +  idx_map   = { 9:0, 3:1, 15:2, 20:3, 7:4 }
    +  post_idx  = [4]  ← postorder の末尟むンデックス
    +
    +dfs(0, 4)  ← inorder 党䜓の範囲
    +  val = postorder[4] = 3    post_idx: [4]→[3]
    +  mid = idx_map[3] = 1
    +  node = TreeNode(3)
    +  ├─ node.right = dfs(2, 4)
    +  │    val = postorder[3] = 20   post_idx: [3]→[2]
    +  │    mid = idx_map[20] = 3
    +  │    node = TreeNode(20)
    +  │    ├─ node.right = dfs(4, 4)
    +  │    │    val = postorder[2] = 7    post_idx: [2]→[1]
    +  │    │    node = TreeNode(7) ← 葉ノヌド巊右None
    +  │    │    return TreeNode(7) ✅
    +  │    └─ node.left = dfs(2, 2)
    +  │         val = postorder[1] = 15   post_idx: [1]→[0]
    +  │         node = TreeNode(15) ← 葉ノヌド
    +  │         return TreeNode(15) ✅
    +  │    return TreeNode(20) ✅
    +  └─ node.left = dfs(0, 0)
    +       val = postorder[0] = 9    post_idx: [0]→[-1]
    +       node = TreeNode(9) ← 葉ノヌド
    +       return TreeNode(9) ✅
    +
    +最終結果:
    +      3
    +     / \
    +    9   20
    +       /  \
    +      15    7   ✅
    +
    +
    + + +
    +

    凊理フロヌチャヌト

    + +
    +

    🗺 フロヌチャヌトの読み方

    +
    +
    + + 楕円緑 開始・終了 +
    +
    + + 四角青 凊理ステップ +
    +
    + + ひし圢黄 条件分岐 +
    +
    + 緑はい + 赀いいえ +
    +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + buildTree 開始 + + + + + + + + inorder が空 + len(inorder) == 0 + + + + はい + + None + + + + いいえ + + + + + ① idx_map を構築 + + {v: i for i, v in enumerate(inorder)} + + + + + + + + ② post_idx を末尟むンデックスに蚭定 + + post_idx = [len(postorder) - 1] + + + + + + + dfs ヘルパヌ関数 + + + + + ③ dfs(0, n-1) 呌び出し + + inorder の党範囲を察象に再垰開始 + + + + + + + + ④ left > right ? + 郚分朚が空の堎合 + + + + はい + + None + + + + いいえ + + + + + â‘€ postorder 末尟からルヌトを取埗 + + val = postorder[post_idx[0]]; post_idx[0] -= 1 + + + + + + + + ⑥ ノヌド䜜成 & mid を O(1) で怜玢 + + node = TreeNode(val) + mid = idx_map[val] # O(1) + + + + + + + + ⑩ 右郚分朚を先に再垰 ★重芁★ + + node.right = dfs(mid + 1, right) + + + + + + + + ⑧ 巊郚分朚を再垰 + + node.left = dfs(left, mid - 1) + + + + + + + + ⑹ 子ノヌドを蚭定しお返す + + return node + + + + + + + + buildTree 完了・朚を返す + +
    + +
    +

    🔎 入力䟋 inorder=[9,3,15,20,7], postorder=[9,15,7,20,3] でのフロヌ远跡

    +
      +
    1. 「buildTree 開始」→ inorder=[9,3,15,20,7] を受け取る空でない → いいえ経路ぞ
    2. +
    3. 「idx_map を構築」→ {9:0, 3:1, 15:2, 20:3, 7:4} を O(n)で生成
    4. +
    5. 「post_idx を蚭定」→ post_idx=[4]末尟むンデックス
    6. +
    7. 「dfs(0, 4) 呌び出し」→ left=0, right=4、終了条件チェック: 0 ≀ 4 → いいえ経路ぞ
    8. +
    9. 「ルヌトを取埗」→ val=postorder[4]=3、post_idx=[3]
    10. +
    11. 「ノヌド䜜成・mid怜玢」→ node=TreeNode(3)、mid=idx_map[3]=1
    12. +
    13. 「右郚分朚を先に再垰」→ dfs(2, 4) でルヌト20の郚分朚を構築
    14. +
    15. 「巊郚分朚を再垰」→ dfs(0, 0) でルヌト9の葉ノヌドを構築
    16. +
    17. 「完了・朚を返す」→ ルヌト TreeNode(3) を返す ✅
    18. +
    +
    + +
    +

    ⚡ なぜ「右を先に再垰する」のか

    +

    Postorderは「巊→右→自分」の順なので、末尟から逆順に取り出すず「自分→右→巊」の順になりたす。post_idxのカヌ゜ルを進めた盎埌に来る次の末尟芁玠は垞に「右郚分朚のルヌト」です。巊を先に再垰しおしたうずカヌ゜ルがずれ、誀ったノヌドをルヌトにしおしたいたす。

    +
    +
    + + +
    +

    蚈算量分析

    + +
    +

    📖 Big-O 蚘法の読み方入力サむズ n が倧きくなるに぀れお凊理時間がどう増えるかの目安

    +
    +
    +
    O(1)
    +
    垞に䞀定
    䟋dict の盎接匕き
    +
    +
    +
    O(n)
    +
    入力に比䟋
    䟋リストを1回走査
    +
    +
    +
    O(n log n)
    +
    n より少し倚い
    䟋゜ヌトアルゎリズム
    +
    +
    +
    O(n²)
    +
    入力の2乗
    䟋二重ルヌプ総圓たり
    +
    +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    皮別蚈算量内蚳
    時間蚈算量O(n)idx_map 構築 O(n) + 各ノヌドを1回だけ凊理 O(n) = O(n)
    空間蚈算量O(n)idx_map O(n) + 再垰スタック O(h)h=朚の高さ、最悪 O(n)+ 出力ノヌド O(n)
    ⚠ 比范ナむヌブ版O(n²)list.index() を毎回呌ぶず O(n) × n回 = O(n²)。n=3000で最倧900䞇操䜜。
    +
    + +
    +

    🔍 なぜこの蚈算量になるのか

    +

    + 時間O(n)の理由idx_mapの構築はenumerate()で1回だけ走査するのでO(n)。dfs()はn個のノヌドそれぞれを1回だけ凊理し、各凊理内のdict怜玢ずpop()はO(1)なので合蚈O(n)。党䜓でO(n)+O(n)=O(n)。 +

    +

    + 空間O(n)の理由idx_mapにn個の゚ントリを栌玍するのでO(n)。再垰スタックは朚の高さh分だけ積たれるが、完党に偏った朚では h=n になるので最悪O(n)。出力の朚もn個のノヌドを䜜成するのでO(n)。 +

    +
    +
    + + +
    +

    📖 甚語集

    +

    このペヌゞで登堎した専門甚語をたずめたした。分からない蚀葉が出おきたずきに参照しおください。

    +
    + +
    + + ▶ 埌順走査Postorder Traversal + +
    + 「巊の子 → 右の子 → 自分ルヌト」の順でノヌドを蚪れる走査方法。 + 配列の末尟芁玠が必ずその郚分朚のルヌトになるずいう性質がこのアルゎリズムの栞心。 + 䟋ルヌト=3の朚では postorder=[9, 15, 7, 20, 3] のように末尟に3が来る。 +
    +
    + +
    + + ▶ 䞭順走査Inorder Traversal + +
    + 「巊の子 → 自分ルヌト → 右の子」の順でノヌドを蚪れる走査方法。 + ルヌトのむンデックスが分かるず、そのむンデックスの巊偎が巊郚分朚・右偎が右郚分朚ずいう分割ができる。 + 䟋inorder=[9, 3, 15, 20, 7]でルヌト=3なら、巊郚分朚=[9]、右郚分朚=[15,20,7]。 +
    +
    + +
    + + ▶ dictハッシュテヌブル / 蟞曞 + +
    + 「キヌ → 倀」の察応を O(1)入力サむズに関わらず垞に䞀定の時間で怜玢できるデヌタ構造。 + 図曞通の玢匕カヌドのようなもので、タむトルキヌから棚番号倀を瞬時に匕ける。 + このアルゎリズムでは idx_map = {v: i for i, v in enumerate(inorder)} で + 「倀 → inorderでの䜍眮番号」を蚘録し、ルヌトの䜍眮を O(n)→O(1)に短瞮しおいる。 +
    +
    + +
    + + ▶ 再垰Recursion + +
    + 関数が自分自身を呌び出すこずで問題を分割しお解く手法。 + 「倧きな問題 = 小さな問題 × 2 + 少しの凊理」の構造を持぀朚の問題に適しおいる。 + 必ず終了条件再垰の底が必芁で、このコヌドでは if left > right: return None がそれにあたる。 +
    +
    + +
    + + ▶ 再垰スタックCall Stack + +
    + 再垰呌び出しが積み重なるメモリ領域。お皿の積み重ねず同じで、最埌に呌んだ関数が最初に終わるLIFO。 + 朚の高さ h 段分だけ積たれるため、完党偏り朚党ノヌドが䞀方向に連なるではh=nになり、デフォルト䞊限1000を超える可胜性がある。 + sys.setrecursionlimit(10_000) で䞊限を匕き䞊げお察凊する。 +
    +
    + +
    + + ▶ dict 内包衚蚘 + +
    + {k: v for ...} の圢で dict を1行で䜜る Python の曞き方。 + 通垞の for ルヌプより CPython最も広く䜿われる Python の実装内郚で最適化された呜什を䜿うため高速。 + {v: i for i, v in enumerate(inorder)} は + 「inorder の倀 → そのむンデックス」を O(n) で䞀括構築する。 +
    +
    + +
    + + ▶ TLETime Limit Exceeded + +
    + LeetCode などの競技プログラミングサむトで、凊理時間が制限を超えたずきに衚瀺される゚ラヌ。 + list.index() を毎回呌ぶナむヌブな実装は O(n²) になり、 + n=3000 で最倧900䞇回の操䜜が必芁になるため TLE になる可胜性がある。 +
    +
    + +
    + + ▶ ルヌト / 葉ノヌドRoot / Leaf Node + +
    + ルヌト根朚の最䞊䜍ノヌド。この問題では postorder の末尟がルヌトになる。 + 葉ノヌド巊右の子を持たない末端ノヌド。再垰の終了時に left == right になるず葉ノヌドが䜜られる。 +
    +
    + +
    + + ▶ 郚分朚Subtree + +
    + ある朚のノヌドを根ルヌトずした朚の䞀郚分のこず。 + このアルゎリズムは「党䜓 = 巊郚分朚 + ルヌト + 右郚分朚」ずいう性質を利甚しお再垰的に問題を分割しおいる。 + dfs(left, right) の匕数 left/right は「inorder 䞊でこの郚分朚が占める範囲のむンデックス」を衚す。 +
    +
    + +
    +
    + + +
    + LeetCode 106 · Python (CPython 3.11+) · Time O(n) · Space O(n) · HashMap + 再垰分割 +
    + +
    + + + + + diff --git a/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html b/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html new file mode 100644 index 00000000..df52c337 --- /dev/null +++ b/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html @@ -0,0 +1,1072 @@ + + + + + +LeetCode 106 · Construct Binary Tree from Inorder and Postorder Traversal + + + + + + + + + + + + + + + + +
    + + + + + +
    +

    アルゎリズム抂芁

    + +
    +

    + 💡 この問題を䞀蚀で蚀うず「2皮類の朚の巡回蚘録Inorder・Postorderを手がかりに、元の二分朚の圢を埩元する問題」 +

    +

    + 二分朚を「巡回する順番のルヌル」が耇数あり、Postorderの末尟芁玠は必ずその郚分朚のルヌト根になりたす。この性質ずHashMapを組み合わせるこずで、配列コピヌなしにO(n)で朚を再構築できたす。 +

    +
    + +
    +

    ⚠ なぜ単玔な方法では解けないのか

    +
      +
    • list.index() でルヌト䜍眮を毎回探すず O(n) × n回  O(n²) になりTLEになるn=3000で最倧900䞇回の操䜜
    • +
    • 配列をスラむスしおコピヌしながら再垰するず O(n²) のメモリが必芁になりMLEになる
    • +
    • Pythonのデフォルト再垰䞊限は1000。偏った朚ではn=3000段の再垰が必芁になるため sys.setrecursionlimit が必須
    • +
    +
    + + +
    +
    +
    O(n)
    +
    時間蚈算量
    +
    +
    +
    O(n)
    +
    空間蚈算量
    +
    +
    +
    HashMap+再垰
    +
    アルゎリズム
    +
    +
    +
    ≀ 3000
    +
    入力サむズ䞊限
    +
    +
    + + +
    +
    +

    入力

    +
    inorder   = [9, 3, 15, 20, 7]
    +postorder = [9, 15, 7, 20, 3]
    +
    +
    +

    出力朚の圢

    +
          3
    +     / \
    +    9   20
    +       /  \
    +      15    7
    +
    +
    +

    + なぜこれが正解か + postorderの末尟3がルヌト → inorderで3の巊が[9]巊郚分朚、右が[15,20,7]右郚分朚ず特定できる。この操䜜を再垰的に繰り返すこずで朚党䜓を埩元できる。 +

    +
    + + +
    +

    ステップバむステップ解説

    +

    ▶ Play ボタンで自動再生、Prev/Next で手動操䜜できたす。

    +
    +
    + + +
    +

    Python 実装

    + +
    +

    📋 このコヌドの構造先に党䜓像を把握しよう

    +
      +
    1. 再垰䞊限匕き䞊げ完党偏り朚でも安党に動䜜させるため sys.setrecursionlimit(10_000) を蚭定
    2. +
    3. HashMap構築idx_map = {v: i for i, v in enumerate(inorder)} で O(1) 怜玢を可胜にする
    4. +
    5. ポむンタ初期化post_idx = [len(postorder) - 1] で末尟からルヌトを消費するカヌ゜ルを蚭眮
    6. +
    7. 再垰ヘルパヌ dfs終了条件チェック → ルヌト取埗 → 右郚分朚を先に再垰 → 巊郚分朚を再垰 → ノヌド返华
    8. +
    +
    + +
    import sys
    +from typing import Optional, List
    +
    +class Solution:
    +    def buildTree(
    +        self,
    +        inorder: List[int],
    +        postorder: List[int]
    +    ) -> Optional[TreeNode]:
    +        # Python のデフォルト再垰䞊限は 1000。
    +        # 完党偏り朚では n=3000 段の再垰が必芁になるため䞊限を匕き䞊げる。
    +        sys.setrecursionlimit(10_000)
    +
    +        # dict 内包衚蚘で「倀 → inorder のむンデックス」を O(n) で1回だけ構築。
    +        # list.index() を毎回呌ぶず O(n²) になるため、事前構築で O(1) 怜玢を実珟。
    +        idx_map: dict[int, int] = {v: i for i, v in enumerate(inorder)}
    +
    +        # post_idx をリストで包む慣甚句。
    +        # 内偎関数から倖偎の int を曞き換えるには nonlocal が必芁だが、
    +        # リストに包むこずで「リストの䞭身を倉える」操䜜になり nonlocal 䞍芁になる。
    +        post_idx: List[int] = [len(postorder) - 1]
    +
    +        def dfs(left: int, right: int) -> Optional[TreeNode]:
    +            # 終了条件巊端が右端を超えた = この範囲に芁玠がない = 郚分朚なし
    +            if left > right:
    +                return None
    +
    +            # postorder の末尟から珟圚の郚分朚のルヌトを取り出す。
    +            # list のむンデックスアクセスは O(1)。カヌ゜ルを1぀前に進める。
    +            val: int = postorder[post_idx[0]]
    +            post_idx[0] -= 1
    +
    +            # ルヌトノヌドを䜜成する。
    +            node = TreeNode(val)
    +
    +            # dict から O(1) でルヌトの inorder 䞊の䜍眮を取埗する。
    +            # この䜍眮より「巊偎」が巊郚分朚、「右偎」が右郚分朚になる。
    +            mid: int = idx_map[val]
    +
    +            # ★重芁★ 右郚分朚を先に再垰する理由
    +            # postorder を末尟から逆順に消費するず「ルヌト→右→巊」の順になる。
    +            # ぀たり次の pop は「右郚分朚のルヌト」を指しおいる。
    +            # 巊を先にするず消費順序がずれお誀った朚になっおしたう。
    +            node.right = dfs(mid + 1, right)  # 右mid+1 〜 right
    +            node.left  = dfs(left, mid - 1)   # 巊left 〜 mid-1
    +
    +            return node
    +
    +        # inorder の党範囲0 〜 n-1を察象に朚を構築しお返す
    +        return dfs(0, len(inorder) - 1)
    + +
    +

    ▶ 入力䟋 inorder=[9,3,15,20,7], postorder=[9,15,7,20,3] での動䜜トレヌス

    +
    事前準備:
    +  idx_map   = { 9:0, 3:1, 15:2, 20:3, 7:4 }
    +  post_idx  = [4]  ← postorder の末尟むンデックス
    +
    +dfs(0, 4)  ← inorder 党䜓の範囲
    +  val = postorder[4] = 3    post_idx: [4]→[3]
    +  mid = idx_map[3] = 1
    +  node = TreeNode(3)
    +  ├─ node.right = dfs(2, 4)
    +  │    val = postorder[3] = 20   post_idx: [3]→[2]
    +  │    mid = idx_map[20] = 3
    +  │    node = TreeNode(20)
    +  │    ├─ node.right = dfs(4, 4)
    +  │    │    val = postorder[2] = 7    post_idx: [2]→[1]
    +  │    │    node = TreeNode(7) ← 葉ノヌド巊右None
    +  │    │    return TreeNode(7) ✅
    +  │    └─ node.left = dfs(2, 2)
    +  │         val = postorder[1] = 15   post_idx: [1]→[0]
    +  │         node = TreeNode(15) ← 葉ノヌド
    +  │         return TreeNode(15) ✅
    +  │    return TreeNode(20) ✅
    +  └─ node.left = dfs(0, 0)
    +       val = postorder[0] = 9    post_idx: [0]→[-1]
    +       node = TreeNode(9) ← 葉ノヌド
    +       return TreeNode(9) ✅
    +
    +最終結果:
    +      3
    +     / \
    +    9   20
    +       /  \
    +      15    7   ✅
    +
    +
    + + +
    +

    凊理フロヌチャヌト

    + +
    +

    🗺 フロヌチャヌトの読み方

    +
    +
    + + 楕円緑 開始・終了 +
    +
    + + 四角青 凊理ステップ +
    +
    + + ひし圢黄 条件分岐 +
    +
    + 緑はい + 赀いいえ +
    +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + buildTree 開始 + + + + + + + + inorder が空 + len(inorder) == 0 + + + + はい + + None + + + + いいえ + + + + + ① idx_map を構築 + + {v: i for i, v in enumerate(inorder)} + + + + + + + + ② post_idx を末尟むンデックスに蚭定 + + post_idx = [len(postorder) - 1] + + + + + + + dfs ヘルパヌ関数 + + + + + ③ dfs(0, n-1) 呌び出し + + inorder の党範囲を察象に再垰開始 + + + + + + + + ④ left > right ? + 郚分朚が空の堎合 + + + + はい + + None + + + + いいえ + + + + + â‘€ postorder 末尟からルヌトを取埗 + + val = postorder[post_idx[0]]; post_idx[0] -= 1 + + + + + + + + ⑥ ノヌド䜜成 & mid を O(1) で怜玢 + + node = TreeNode(val) + mid = idx_map[val] # O(1) + + + + + + + + ⑩ 右郚分朚を先に再垰 ★重芁★ + + node.right = dfs(mid + 1, right) + + + + + + + + ⑧ 巊郚分朚を再垰 + + node.left = dfs(left, mid - 1) + + + + + + + + ⑹ 子ノヌドを蚭定しお返す + + return node + + + + + + + + buildTree 完了・朚を返す + +
    + +
    +

    🔎 入力䟋 inorder=[9,3,15,20,7], postorder=[9,15,7,20,3] でのフロヌ远跡

    +
      +
    1. 「buildTree 開始」→ inorder=[9,3,15,20,7] を受け取る空でない → いいえ経路ぞ
    2. +
    3. 「idx_map を構築」→ {9:0, 3:1, 15:2, 20:3, 7:4} を O(n)で生成
    4. +
    5. 「post_idx を蚭定」→ post_idx=[4]末尟むンデックス
    6. +
    7. 「dfs(0, 4) 呌び出し」→ left=0, right=4、終了条件チェック: 0 ≀ 4 → いいえ経路ぞ
    8. +
    9. 「ルヌトを取埗」→ val=postorder[4]=3、post_idx=[3]
    10. +
    11. 「ノヌド䜜成・mid怜玢」→ node=TreeNode(3)、mid=idx_map[3]=1
    12. +
    13. 「右郚分朚を先に再垰」→ dfs(2, 4) でルヌト20の郚分朚を構築
    14. +
    15. 「巊郚分朚を再垰」→ dfs(0, 0) でルヌト9の葉ノヌドを構築
    16. +
    17. 「完了・朚を返す」→ ルヌト TreeNode(3) を返す ✅
    18. +
    +
    + +
    +

    ⚡ なぜ「右を先に再垰する」のか

    +

    Postorderは「巊→右→自分」の順なので、末尟から逆順に取り出すず「自分→右→巊」の順になりたす。post_idxのカヌ゜ルを進めた盎埌に来る次の末尟芁玠は垞に「右郚分朚のルヌト」です。巊を先に再垰しおしたうずカヌ゜ルがずれ、誀ったノヌドをルヌトにしおしたいたす。

    +
    +
    + + +
    +

    蚈算量分析

    + +
    +

    📖 Big-O 蚘法の読み方入力サむズ n が倧きくなるに぀れお凊理時間がどう増えるかの目安

    +
    +
    +
    O(1)
    +
    垞に䞀定
    䟋dict の盎接匕き
    +
    +
    +
    O(n)
    +
    入力に比䟋
    䟋リストを1回走査
    +
    +
    +
    O(n log n)
    +
    n より少し倚い
    䟋゜ヌトアルゎリズム
    +
    +
    +
    O(n²)
    +
    入力の2乗
    䟋二重ルヌプ総圓たり
    +
    +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    皮別蚈算量内蚳
    時間蚈算量O(n)idx_map 構築 O(n) + 各ノヌドを1回だけ凊理 O(n) = O(n)
    空間蚈算量O(n)idx_map O(n) + 再垰スタック O(h)h=朚の高さ、最悪 O(n)+ 出力ノヌド O(n)
    ⚠ 比范ナむヌブ版O(n²)list.index() を毎回呌ぶず O(n) × n回 = O(n²)。n=3000で最倧900䞇操䜜。
    +
    + +
    +

    🔍 なぜこの蚈算量になるのか

    +

    + 時間O(n)の理由idx_mapの構築はenumerate()で1回だけ走査するのでO(n)。dfs()はn個のノヌドそれぞれを1回だけ凊理し、各凊理内のdict怜玢ずpop()はO(1)なので合蚈O(n)。党䜓でO(n)+O(n)=O(n)。 +

    +

    + 空間O(n)の理由idx_mapにn個の゚ントリを栌玍するのでO(n)。再垰スタックは朚の高さh分だけ積たれるが、完党に偏った朚では h=n になるので最悪O(n)。出力の朚もn個のノヌドを䜜成するのでO(n)。 +

    +
    +
    + + +
    +

    📖 甚語集

    +

    このペヌゞで登堎した専門甚語をたずめたした。分からない蚀葉が出おきたずきに参照しおください。

    +
    + +
    + + ▶ 埌順走査Postorder Traversal + +
    + 「巊の子 → 右の子 → 自分ルヌト」の順でノヌドを蚪れる走査方法。 + 配列の末尟芁玠が必ずその郚分朚のルヌトになるずいう性質がこのアルゎリズムの栞心。 + 䟋ルヌト=3の朚では postorder=[9, 15, 7, 20, 3] のように末尟に3が来る。 +
    +
    + +
    + + ▶ 䞭順走査Inorder Traversal + +
    + 「巊の子 → 自分ルヌト → 右の子」の順でノヌドを蚪れる走査方法。 + ルヌトのむンデックスが分かるず、そのむンデックスの巊偎が巊郚分朚・右偎が右郚分朚ずいう分割ができる。 + 䟋inorder=[9, 3, 15, 20, 7]でルヌト=3なら、巊郚分朚=[9]、右郚分朚=[15,20,7]。 +
    +
    + +
    + + ▶ dictハッシュテヌブル / 蟞曞 + +
    + 「キヌ → 倀」の察応を O(1)入力サむズに関わらず垞に䞀定の時間で怜玢できるデヌタ構造。 + 図曞通の玢匕カヌドのようなもので、タむトルキヌから棚番号倀を瞬時に匕ける。 + このアルゎリズムでは idx_map = {v: i for i, v in enumerate(inorder)} で + 「倀 → inorderでの䜍眮番号」を蚘録し、ルヌトの䜍眮を O(n)→O(1)に短瞮しおいる。 +
    +
    + +
    + + ▶ 再垰Recursion + +
    + 関数が自分自身を呌び出すこずで問題を分割しお解く手法。 + 「倧きな問題 = 小さな問題 × 2 + 少しの凊理」の構造を持぀朚の問題に適しおいる。 + 必ず終了条件再垰の底が必芁で、このコヌドでは if left > right: return None がそれにあたる。 +
    +
    + +
    + + ▶ 再垰スタックCall Stack + +
    + 再垰呌び出しが積み重なるメモリ領域。お皿の積み重ねず同じで、最埌に呌んだ関数が最初に終わるLIFO。 + 朚の高さ h 段分だけ積たれるため、完党偏り朚党ノヌドが䞀方向に連なるではh=nになり、デフォルト䞊限1000を超える可胜性がある。 + sys.setrecursionlimit(10_000) で䞊限を匕き䞊げお察凊する。 +
    +
    + +
    + + ▶ dict 内包衚蚘 + +
    + {k: v for ...} の圢で dict を1行で䜜る Python の曞き方。 + 通垞の for ルヌプより CPython最も広く䜿われる Python の実装内郚で最適化された呜什を䜿うため高速。 + {v: i for i, v in enumerate(inorder)} は + 「inorder の倀 → そのむンデックス」を O(n) で䞀括構築する。 +
    +
    + +
    + + ▶ TLETime Limit Exceeded + +
    + LeetCode などの競技プログラミングサむトで、凊理時間が制限を超えたずきに衚瀺される゚ラヌ。 + list.index() を毎回呌ぶナむヌブな実装は O(n²) になり、 + n=3000 で最倧900䞇回の操䜜が必芁になるため TLE になる可胜性がある。 +
    +
    + +
    + + ▶ ルヌト / 葉ノヌドRoot / Leaf Node + +
    + ルヌト根朚の最䞊䜍ノヌド。この問題では postorder の末尟がルヌトになる。 + 葉ノヌド巊右の子を持たない末端ノヌド。再垰の終了時に left == right になるず葉ノヌドが䜜られる。 +
    +
    + +
    + + ▶ 郚分朚Subtree + +
    + ある朚のノヌドを根ルヌトずした朚の䞀郚分のこず。 + このアルゎリズムは「党䜓 = 巊郚分朚 + ルヌト + 右郚分朚」ずいう性質を利甚しお再垰的に問題を分割しおいる。 + dfs(left, right) の匕数 left/right は「inorder 䞊でこの郚分朚が占める範囲のむンデックス」を衚す。 +
    +
    + +
    +
    + + +
    + LeetCode 106 · Python (CPython 3.11+) · Time O(n) · Space O(n) · HashMap + 再垰分割 +
    + +
    + + + + + diff --git a/public/index.html b/public/index.html index 87b38442..872c1830 100644 --- a/public/index.html +++ b/public/index.html @@ -416,7 +416,7 @@

    🧪 Algorithm Study Index

    -

    172 interactive lessons across 6 domains

    +

    173 interactive lessons across 6 domains

    @@ -431,9 +431,9 @@

    - + @@ -471,6 +471,7 @@

  • 🧩LeetCode 103 – Binary Tree Zigzag Level Order TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/README_React.html
  • 🧩LeetCode 104 · Maximum Depth of Binary TreeAlgorithm/BinaryTree/claude sonnet 4.6 extended/104. Maximum Depth of Binary Tree/README_React.html
  • 🧩LeetCode 105 – Construct Binary Tree from Preorder and Inorder TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html
  • +
  • 🧩LeetCode 106 · Construct Binary Tree from Inorder and Postorder TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html
  • 🧩LeetCode 5: Longest Palindromic Substring - 䞭心展開法Algorithm/ExpandAroundCenter/leetcode/5. Longest Palindromic Substring/Claude/README.html
  • 🧩LeetCode 66: Plus One - 右から巊ぞの繰り䞊がり凊理Algorithm/Other/leetcode/66. Plus One/Claude Sonnet 4.5/README_react.html
  • 🧩LeetCode 67: Add Binary - 二進数加算Algorithm/TwoPointers/leetcode/67. Add Binary/Claude/README_react.html
  • @@ -650,6 +651,7 @@

  • 🧩LeetCode 103 – Binary Tree Zigzag Level Order TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/README_React.html
  • 🧩LeetCode 104 · Maximum Depth of Binary TreeAlgorithm/BinaryTree/claude sonnet 4.6 extended/104. Maximum Depth of Binary Tree/README_React.html
  • 🧩LeetCode 105 – Construct Binary Tree from Preorder and Inorder TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html
  • +
  • 🧩LeetCode 106 · Construct Binary Tree from Inorder and Postorder TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html
  • 🧩LeetCode 5: Longest Palindromic Substring - 䞭心展開法Algorithm/ExpandAroundCenter/leetcode/5. Longest Palindromic Substring/Claude/README.html
  • 🧩LeetCode 66: Plus One - 右から巊ぞの繰り䞊がり凊理Algorithm/Other/leetcode/66. Plus One/Claude Sonnet 4.5/README_react.html
  • 🧩LeetCode 67: Add Binary - 二進数加算Algorithm/TwoPointers/leetcode/67. Add Binary/Claude/README_react.html
  • @@ -827,7 +829,7 @@

    🧪 - Generated on 2026-04-22 + Generated on 2026-04-26
    diff --git a/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html b/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html index 456a4e98..69b2244d 100644 --- a/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html +++ b/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html @@ -218,7 +218,7 @@

    Optional[TreeNode]: + def dfs(left: int, right: int) -> Optional[TreeNode]: # 終了条件巊端が右端を超えた = この範囲に芁玠がない = 郚分朚なし - if left > right: + if left > right: return None # postorder の末尟から珟圚の郚分朚のルヌトを取り出す。 @@ -1066,7 +1066,9 @@

    {currentStepData.tit root.render(React.createElement(StepsApp)); // Re-highlight code after React renders -setTimeout(() => { if (window.Prism) Prism.highlightAll(); }, 300); +requestAnimationFrame(() => { + if (window.Prism) Prism.highlightAllUnder(document.getElementById("react-steps")); +}); diff --git a/public/index.html b/public/index.html index 872c1830..d612a190 100644 --- a/public/index.html +++ b/public/index.html @@ -829,7 +829,7 @@

    🧪 - Generated on 2026-04-26 + Generated on 2026-04-27
    +g)"; + }); + }); + + + diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/Construct-Binary-Tree-from-Inorder-and-Postorder-Traversal_Python.md b/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/Construct-Binary-Tree-from-Inorder-and-Postorder-Traversal_Python.md index 20522aec..e67a8d16 100644 --- a/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/Construct-Binary-Tree-from-Inorder-and-Postorder-Traversal_Python.md +++ b/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/Construct-Binary-Tree-from-Inorder-and-Postorder-Traversal_Python.md @@ -118,14 +118,16 @@ class Solution: f"inorder({len(inorder)}) ず postorder({len(postorder)}) の長さが䞀臎したせん" ) - # 空入力はそのたた None を返す゚ラヌではなく正垞な゚ッゞケヌス + # 空入力ぱラヌずする if not inorder: - return None + raise ValueError("入力が空です") # 芁玠の型チェックany() は最初に True が芋぀かった時点で停止するC実装の関数 # all() の逆。「1぀でも非intがあれば True」 if any(not isinstance(x, int) for x in inorder): raise TypeError("inorder の党芁玠は int である必芁がありたす") + if any(not isinstance(x, int) for x in postorder): + raise TypeError("postorder の党芁玠は int である必芁がありたす") # ── 再垰深床の蚭定 ───────────────────────────────────────────────── # Python のデフォルト再垰䞊限は1000。 diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html b/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html index 59ab063f..ce4b8ca0 100644 --- a/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html +++ b/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html @@ -1065,6 +1065,15 @@

    {currentStepData.tit const root = ReactDOM.createRoot(document.getElementById("react-steps")); root.render(React.createElement(StepsApp)); +// Re-highlight code after React renders +requestAnimationFrame(() => { + if (window.Prism) Prism.highlightAll(); +}); + + + +; + // Re-highlight code after React renders requestAnimationFrame(() => { if (window.Prism) Prism.highlightAllUnder(document.getElementById("react-steps")); diff --git a/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html b/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html index 69b2244d..f27084fc 100644 --- a/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html +++ b/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html @@ -1020,7 +1020,7 @@

    = 2 && PREORDER.slice(0, activeStep - 1).includes(v) + activeStep >= 2 && PREORDER.slice(0, activeStep === 6 ? 5 : Math.max(0, activeStep - 2)).includes(v) ? "bg-emerald-200 border-emerald-500 text-emerald-900" : "bg-white border-slate-200 text-slate-600" ].join(" ")} @@ -1079,3 +1079,9 @@

    +g)"; + }); + }); + + + diff --git a/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html b/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html index 5b6a9712..d92b11e2 100644 --- a/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html +++ b/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html @@ -1065,6 +1065,15 @@

    {currentStepData.tit const root = ReactDOM.createRoot(document.getElementById("react-steps")); root.render(React.createElement(StepsApp)); +// Re-highlight code after React renders +requestAnimationFrame(() => { + if (window.Prism) Prism.highlightAll(); +}); + + + +; + // Re-highlight code after React renders requestAnimationFrame(() => { if (window.Prism) Prism.highlightAllUnder(document.getElementById("react-steps")); diff --git a/public/index.html b/public/index.html index b7ba2e9c..d612a190 100644 --- a/public/index.html +++ b/public/index.html @@ -505,8 +505,8 @@

  • 🧩Search in Rotated Sorted Array II - Technical AnalysisAlgorithm/BinarySearch/leetcode/81. Search in Rotated Sorted Array II/Claude/README.html
  • 🧩Set Matrix Zeroes Algorithm - Python ImplementationAlgorithm/Other/leetcode/73. Set Matrix Zeroes/Claude/README.html
  • 🧩Sort Colors Algorithm - Interactive Technical GuideAlgorithm/Dutch National Flag/leetcode/75. Sort Colors/Claude/README.html
  • -
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/54. Spiral Matrix/Claude/README.html
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/59. Spiral Matrix II/Claude/README.html
  • +
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/54. Spiral Matrix/Claude/README.html
  • 🧩Subsets II - 反埩的拡匵法による重耇排陀 | アルゎリズム解説Algorithm/Other/leetcode/90. Subsets II/Claude/README.html
  • 🧩Two-Pointer Algorithm: Remove Duplicates from Sorted Array IIAlgorithm/TwoPointers/leetcode/80. Remove Duplicates from Sorted Array II/Claude/README.html
  • 🧩TypeScript Binary Search Performance AnalysisAlgorithm/BinarySearch/leetcode/34. Find First and Last Position of Element in Sorted Array/READEME-typescript.html
  • @@ -685,8 +685,8 @@

  • 🧩Search in Rotated Sorted Array II - Technical AnalysisAlgorithm/BinarySearch/leetcode/81. Search in Rotated Sorted Array II/Claude/README.html
  • 🧩Set Matrix Zeroes Algorithm - Python ImplementationAlgorithm/Other/leetcode/73. Set Matrix Zeroes/Claude/README.html
  • 🧩Sort Colors Algorithm - Interactive Technical GuideAlgorithm/Dutch National Flag/leetcode/75. Sort Colors/Claude/README.html
  • -
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/54. Spiral Matrix/Claude/README.html
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/59. Spiral Matrix II/Claude/README.html
  • +
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/54. Spiral Matrix/Claude/README.html
  • 🧩Subsets II - 反埩的拡匵法による重耇排陀 | アルゎリズム解説Algorithm/Other/leetcode/90. Subsets II/Claude/README.html
  • 🧩Two-Pointer Algorithm: Remove Duplicates from Sorted Array IIAlgorithm/TwoPointers/leetcode/80. Remove Duplicates from Sorted Array II/Claude/README.html
  • 🧩TypeScript Binary Search Performance AnalysisAlgorithm/BinarySearch/leetcode/34. Find First and Last Position of Element in Sorted Array/READEME-typescript.html
  • From 66dbb74511349b8d4f2fbb81a998254bfc48fb2c Mon Sep 17 00:00:00 2001 From: myoshi2891 <96483039+myoshi2891@users.noreply.github.com> Date: Mon, 27 Apr 2026 07:26:17 +0000 Subject: [PATCH 12/13] build: auto-generate public directory --- public/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/index.html b/public/index.html index d612a190..b7ba2e9c 100644 --- a/public/index.html +++ b/public/index.html @@ -505,8 +505,8 @@

  • 🧩Search in Rotated Sorted Array II - Technical AnalysisAlgorithm/BinarySearch/leetcode/81. Search in Rotated Sorted Array II/Claude/README.html
  • 🧩Set Matrix Zeroes Algorithm - Python ImplementationAlgorithm/Other/leetcode/73. Set Matrix Zeroes/Claude/README.html
  • 🧩Sort Colors Algorithm - Interactive Technical GuideAlgorithm/Dutch National Flag/leetcode/75. Sort Colors/Claude/README.html
  • -
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/59. Spiral Matrix II/Claude/README.html
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/54. Spiral Matrix/Claude/README.html
  • +
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/59. Spiral Matrix II/Claude/README.html
  • 🧩Subsets II - 反埩的拡匵法による重耇排陀 | アルゎリズム解説Algorithm/Other/leetcode/90. Subsets II/Claude/README.html
  • 🧩Two-Pointer Algorithm: Remove Duplicates from Sorted Array IIAlgorithm/TwoPointers/leetcode/80. Remove Duplicates from Sorted Array II/Claude/README.html
  • 🧩TypeScript Binary Search Performance AnalysisAlgorithm/BinarySearch/leetcode/34. Find First and Last Position of Element in Sorted Array/READEME-typescript.html
  • @@ -685,8 +685,8 @@

  • 🧩Search in Rotated Sorted Array II - Technical AnalysisAlgorithm/BinarySearch/leetcode/81. Search in Rotated Sorted Array II/Claude/README.html
  • 🧩Set Matrix Zeroes Algorithm - Python ImplementationAlgorithm/Other/leetcode/73. Set Matrix Zeroes/Claude/README.html
  • 🧩Sort Colors Algorithm - Interactive Technical GuideAlgorithm/Dutch National Flag/leetcode/75. Sort Colors/Claude/README.html
  • -
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/59. Spiral Matrix II/Claude/README.html
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/54. Spiral Matrix/Claude/README.html
  • +
  • 🧩Spiral Matrix Algorithm AnalysisAlgorithm/Other/leetcode/59. Spiral Matrix II/Claude/README.html
  • 🧩Subsets II - 反埩的拡匵法による重耇排陀 | アルゎリズム解説Algorithm/Other/leetcode/90. Subsets II/Claude/README.html
  • 🧩Two-Pointer Algorithm: Remove Duplicates from Sorted Array IIAlgorithm/TwoPointers/leetcode/80. Remove Duplicates from Sorted Array II/Claude/README.html
  • 🧩TypeScript Binary Search Performance AnalysisAlgorithm/BinarySearch/leetcode/34. Find First and Last Position of Element in Sorted Array/READEME-typescript.html
  • From 88ad612e8f0e2f558df8e32bff940b596308bbe1 Mon Sep 17 00:00:00 2001 From: myoshizumi Date: Mon, 27 Apr 2026 16:44:37 +0900 Subject: [PATCH 13/13] docs(105, 106): minor refinements to React READMEs --- .../README_React.html | 6 ------ .../README_React.html | 9 --------- .../README_React.html | 6 ------ .../README_React.html | 9 --------- 4 files changed, 30 deletions(-) diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html b/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html index 5764eb0f..5b630af4 100644 --- a/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html +++ b/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html @@ -1079,9 +1079,3 @@

    -g)"; - }); - }); - - - diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html b/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html index ce4b8ca0..67a154f0 100644 --- a/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html +++ b/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html @@ -1072,12 +1072,3 @@

    {currentStepData.tit -; - -// Re-highlight code after React renders -requestAnimationFrame(() => { - if (window.Prism) Prism.highlightAllUnder(document.getElementById("react-steps")); -}); - - - diff --git a/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html b/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html index f27084fc..efc7cefa 100644 --- a/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html +++ b/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html @@ -1079,9 +1079,3 @@

    -g)"; - }); - }); - - - diff --git a/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html b/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html index d92b11e2..7f64755d 100644 --- a/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html +++ b/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html @@ -1072,12 +1072,3 @@

    {currentStepData.tit -; - -// Re-highlight code after React renders -requestAnimationFrame(() => { - if (window.Prism) Prism.highlightAllUnder(document.getElementById("react-steps")); -}); - - -