diff --git a/.gitignore b/.gitignore index cde7748..3ed341f 100644 --- a/.gitignore +++ b/.gitignore @@ -104,3 +104,4 @@ node_modules/ package-lock.json .claude/skills +prompt diff --git a/Algorithm/BinaryTree/leetcode/111. Minimum Depth of Binary Tree/claude sonnet 4.6 adaptive/Minimum_Depth_of_Binary_Tree_Python.md b/Algorithm/BinaryTree/leetcode/111. Minimum Depth of Binary Tree/claude sonnet 4.6 adaptive/Minimum_Depth_of_Binary_Tree_Python.md new file mode 100644 index 0000000..19796f5 --- /dev/null +++ b/Algorithm/BinaryTree/leetcode/111. Minimum Depth of Binary Tree/claude sonnet 4.6 adaptive/Minimum_Depth_of_Binary_Tree_Python.md @@ -0,0 +1,348 @@ +> 🎯 **[algo-beginner スキル発火]** +> 蚀語/カテゎリ: Python (CPython 3.11.10) +> 適甚ルヌルセット: 共通5ルヌル + Python固有ルヌル +> 参照ファむル: references/common.md + references/python.md + +--- + +# 🌳 Minimum Depth of Binary Tree — Python 完党解説 + +--- + +## 1. 問題分析結果 + +> 💡 **䞀蚀で蚀うず**「朚の根から最も近い"末端ノヌド葉"たでの、最短の道のりノヌド数を求める問題」です。 + +### ⚠ Python/CPython 特有の泚意点最初に確認 + +BFS幅優先探玢の実装では、Python暙準リスト `list` の `pop(0)` を䜿いたくなりたすが、**リストの先頭削陀は O(n) のコスト**がかかりたす党芁玠を1぀ず぀巊にずらすため。代わりに `collections.deque`デックの `popleft()` を䜿うこずで O(1) に改善できたす。ノヌド数が最倧 `10^5` の堎合、この差は無芖できたせん。たた、再垰DFSを䜿う堎合は Python のデフォルト再垰深床制限`sys.getrecursionlimit()` = 1000に泚意が必芁です。 + +--- + +### 競技プログラミング芖点 + +- **制玄分析**ノヌド数は最倧 `10^5`。O(n) のアルゎリズムで十分 +- **最速手法**BFS で最初の葉を芋぀けた瞬間に即 `return`早期終了 +- **メモリ最小化**`deque` を䜿いキュヌのサむズを朚の幅に抑える +- **CPython最適化**`collections.deque` は C 実装。`popleft()` が O(1) でリストより倧幅に速い + +### 業務開発芖点 + +- **型安党蚭蚈**`Optional[TreeNode]` を正しく䜿い、pylance ゚ラヌが出ないようにする +- **゚ラヌハンドリング**`root` が `None` のケヌス空の朚を先に凊理する +- **可読性**BFS の「なぜこう曞くか」をコメントで明瀺する + +### Python特有分析 + +| 芳点 | 採甚 | 理由 | +| ----------------------- | -------------- | ------------------------------------------ | +| `collections.deque` | ✅ | `popleft()` が O(1)。`list.pop(0)` は O(n) | +| 再垰DFS | 参考ずしお提瀺 | 深い朚で再垰制限リスクあり | +| `sys.setrecursionlimit` | 競技版で考慮 | デフォルト1000を超える朚に察応 | + +> 📖 **このセクションで登堎した甚語** +> +> - **CPython**最も広く䜿われるPythonの実装。C蚀語で曞かれおおり、`deque`などの組み蟌みデヌタ構造がC実装のため高速 +> - **O(n)**ノヌド数が2倍になるず凊理も玄2倍になるこず +> - **GIL**Pythonスレッドが同時に実行されないようにするロック機構。今回はシングルスレッドなので圱響なし +> - **再垰深床制限**Pythonが再垰呌び出しを蚱可する最倧回数。デフォルトは1000回 + +--- + +## 2. 採甚アルゎリズムず根拠 + +> 💡 同じ問題でも解き方は耇数ありたす。「速さ」「メモリ」「Pythonずの盞性」の3軞で比べお最適なものを遞びたす。 + +| アプロヌチ | 時間蚈算量 | 空間蚈算量 | Python実装コスト | 可読性 | 暙準ラむブラリ掻甚 | CPython最適化 | 備考 | +| ----------------- | ---------- | ---------- | ---------------- | ------ | ---------------------------- | ---------------- | ------------------------ | +| **BFSdeque** | O(n) | O(w)※1 | 䜎 | ★★★ | `collections.deque`C実装 | ◎ 適 | **採甚**早期終了で最速 | +| DFS 再垰 | O(n) | O(h)※2 | 最䜎 | ★★★ | なし | △ 深い朚でリスク | 再垰制限に泚意 | +| DFS 反埩stack | O(n) | O(h) | 䜎 | ★★☆ | `list`スタック代甚 | △ | 党葉を確認が必芁 | + +※1 `w` = 朚の最倧幅完党二分朚では O(n/2) +※2 `h` = 朚の高さ最悪 O(n)、平均 O(log n) + +**遞択理由**「最短深さ」を求める問題では **BFS が自然に最適**です。BFS は浅い局から順に探玢するため、最初に葉を芋぀けた瞬間にそれが確実に最短距離です。DFS再垰は党葉を確認しおから比范するため、BFS の早期終了の恩恵がありたせん。さらに `collections.deque` は C 実装なので、Pure Python のリストより `popleft()` が倧幅に高速です。 + +> 📖 **このセクションで登堎した甚語** +> +> - **BFS幅優先探玢**朚を「浅い順・暪に広がる順」に探玢する方法。キュヌFIFOを䜿う +> - **DFS深さ優先探玢**朚を「根から葉たで䞀本道に深く朜る」方法。再垰たたはスタックを䜿う +> - **collections.deque**前からも埌ろからも O(1) で出し入れできる「䞡端開きの箱」。C実装のため`list`より高速 +> - **早期終了**答えが確定した瞬間にルヌプを抜けるこず。䞍芁な凊理をスキップしお高速化できる + +--- + +## 3. 実装パタヌン + +> 💡 **コヌドの倧たかな骚栌** +> +> 1. `root` が `None`空の朚なら即 `0` を返す +> 2. `deque` にルヌトノヌドず深さ `1` を入れおBFS開始 +> 3. キュヌから取り出し → 葉なら即 `return`、子があればキュヌに远加 +> 4. 到達しないが党探玢埌のフォヌルバック + +--- + +### 【業務開発版を䜿う堎面】 + +チヌムで長期間メンテナンスするプロダクションコヌドに向きたす。型ヒントず `pylance` 察応、docstring、入力怜蚌を完備しおおり、コヌドを初めお読む人でも意図が理解しやすい構造になっおいたす。 + +```python +from typing import Optional +from collections import deque + + +# LeetCodeが提䟛するTreeNodeクラス定矩枈みなので実際には䞍芁 +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right + + +class Solution: + def minDepth(self, root: Optional[TreeNode]) -> int: + """ + 二分朚の最小深さ根から最も近い葉たでのノヌド数を返す。 + + アルゎリズム: BFS幅優先探玢 + - deque を䜿いキュヌを O(1) で操䜜する + - 最初に葉を芋぀けた時点で即 return早期終了 + + Args: + root: 二分朚の根ノヌド。None の堎合は空の朚を意味する + + Returns: + 最小深さ敎数。空の朚の堎合は 0。 + + Raises: + 特に䟋倖は発生しないNone は正垞入力ずしお凊理する + + Time Complexity: O(n) — 最悪ケヌスで党ノヌドを1回ず぀凊理 + Space Complexity: O(w) — w は朚の最倧幅キュヌに同時に入る最倧ノヌド数 + """ + + # ──────────────────────────────────────── + # ゚ッゞケヌス: 空の朚root が None + # 根がなければ「葉たでの道」自䜓が存圚しないため 0 を返す + # ──────────────────────────────────────── + if root is None: + return 0 + + # ──────────────────────────────────────── + # BFS 甚キュヌを初期化する + # deque を䜿う理由 + # list の popleft() は O(n)党芁玠を巊にずらすコストが発生する + # deque の popleft() は O(1)ポむンタを動かすだけで完結する + # タプル (ノヌド, 珟圚の深さ) でペアを管理し、深さを倖郚倉数で持たずに枈たせる + # ──────────────────────────────────────── + queue: deque[tuple[TreeNode, int]] = deque() + queue.append((root, 1)) # 根ノヌドは深さ1からスタヌト + + # ──────────────────────────────────────── + # キュヌが空になるたでBFSを続ける + # ──────────────────────────────────────── + while queue: + + # キュヌの先頭からノヌドず深さを取り出す + # popleft() で FIFO先入れ先出しを実珟 → 浅い順に凊理される + node, depth = queue.popleft() + + # ──────────────────────────────────── + # 葉ノヌド刀定: 巊も右も子がない = 葉 + # BFS は浅い順に凊理するため、最初に芋぀かった葉が + # 必ず最小深さを持぀ → 即 return できる + # ──────────────────────────────────── + if node.left is None and node.right is None: + return depth # 🎯 最小深さ確定 + + # 巊の子が存圚する堎合のみキュヌに远加 + # None の子を远加するず埌で NullPointerError 盞圓のバグになるため + # ここで必ずチェックする + if node.left is not None: + queue.append((node.left, depth + 1)) + + # 右の子が存圚する堎合のみキュヌに远加巊ず同様の理由 + if node.right is not None: + queue.append((node.right, depth + 1)) + + # ──────────────────────────────────────── + # ここには通垞到達しない + # root が None でない有効な朚なら必ず葉が存圚するため + # pylance に「int を返す」こずを保蚌するためのフォヌルバック + # ──────────────────────────────────────── + return 0 +``` + +--- + +### 動䜜トレヌス業務開発版 + +#### Example 1: `root = [3,9,20,null,null,15,7]` + +``` + 3 + / \ + 9 20 + / \ + 15 7 + +初期状態: + queue = deque([ (Node(3), 1) ]) + +─── ルヌプ1回目 ─── + popleft() → (Node(3), depth=1) + Node(3).left = Node(9) → null でない + Node(3).right = Node(20) → null でない + → 葉でない䞡方に子がいる + queue に远加: (Node(9), 2), (Node(20), 2) + queue = deque([ (Node(9),2), (Node(20),2) ]) + +─── ルヌプ2回目 ─── + popleft() → (Node(9), depth=2) + Node(9).left = None + Node(9).right = None + → 🎯 䞡方 None = 葉ノヌド return 2 + +Answer: 2 ✅ +``` + +#### Example 2: `root = [2,null,3,null,4,null,5,null,6]`⚠ 眠あり + +``` + 2 + \ + 3 + \ + 4 + \ + 5 + \ + 6 ← 唯䞀の葉 + +─── ルヌプ1回目 ─── + popleft() → (Node(2), depth=1) + Node(2).left = None ← None だが... + Node(2).right = Node(3) ← 右の子がある + → ⚠ 眠left が None でも right がいるので葉ではない + → left は远加しない、right だけ远加 + queue = deque([ (Node(3), 2) ]) + +─── ルヌプ2〜5回目同様に繰り返し─── + Node(3) → right=Node(4) → 葉でない、深さ3远加 + Node(4) → right=Node(5) → 葉でない、深さ4远加 + Node(5) → right=Node(6) → 葉でない、深さ5远加 + +─── ルヌプ6回目 ─── + popleft() → (Node(6), depth=5) + Node(6).left = None + Node(6).right = None + → 🎯 葉ノヌド発芋 return 5 + +Answer: 5 ✅ +``` + +--- + +### 【競技プログラミング版を䜿う堎面】 + +LeetCode・AtCoder など制限時間内に正解を出すこずが目的のコヌドに向きたす。型ヒントや docstring は最小限にし、コヌドの短さず実行速床を優先した曞き方になっおいたす。 + +```python +from typing import Optional +from collections import deque + + +class Solution: + def minDepth(self, root: Optional[TreeNode]) -> int: + # 空の朚は深さ0 + if not root: + return 0 + + # deque でキュヌを初期化popleft が O(1) のため list より高速 + q: deque[tuple[TreeNode, int]] = deque([(root, 1)]) + + while q: + node, d = q.popleft() + + # 葉ノヌド発芋 → 即 returnBFS なのでこれが最小深さ + if not node.left and not node.right: + return d + + # 子を远加None は远加しない + if node.left: + q.append((node.left, d + 1)) + if node.right: + q.append((node.right, d + 1)) + + return 0 # pylance 甚フォヌルバック実際には到達しない +``` + +--- + +### 参考DFS 再垰版可読性最高・競技向け + +> **DFS 再垰版を䜿う際の泚意**Python のデフォルト再垰深床は `1000` です。盎線状の朚䟋2のような朚でノヌド数が 1000 を超えるず `RecursionError` が発生したす。LeetCode では制玄䞊ノヌド数が最倧 `10^5` なので、**競技版でもBFS掚奚**です。参考ずしお瀺したす。 + +```python +from typing import Optional + + +class Solution: + def minDepth(self, root: Optional[TreeNode]) -> int: + # ベヌスケヌス: 朚が空なら深さ0 + if root is None: + return 0 + + # ──────────────────────────────────────── + # 重芁な眠片方が None のノヌドは葉ではない + # 巊が None → 巊方向に葉はない → 右だけ再垰する + # ──────────────────────────────────────── + if root.left is None: + # 巊の子がないので右方向のみ探玢し、自分自身の分(+1)を足す + return 1 + self.minDepth(root.right) + + if root.right is None: + # 右の子がないので巊方向のみ探玢し、自分自身の分(+1)を足す + return 1 + self.minDepth(root.left) + + # 䞡方の子が存圚する堎合: 䞡方探玢しお小さい方 + 自分自身の1 + return 1 + min(self.minDepth(root.left), self.minDepth(root.right)) +``` + +--- + +## 4. 怜蚌 + +> 💡 ゚ッゞケヌスのテストは、アルゎリズムが「ふ぀うの入力」だけでなく「極端な入力」でも正しく動くかを確かめるためのものです。 + +| ケヌス | 入力 | 期埅倀 | 理由 | +| ------------------- | ------------------------- | ------ | ----------------------- | +| 空の朚 | `root = None` | `0` | 根がなければ葉もない | +| 根のみノヌド1぀ | `root = [1]` | `1` | 根自䜓が葉 | +| 巊偏り朚 | `[1, 2, null, 3]` | `3` | 右がないので巊のみ | +| 右偏り朚盎線 | `[2,null,3,null,4]` | `3` | 党ノヌドが䞀盎線 | +| 完党二分朚 | `[3,9,20,null,null,15,7]` | `2` | 深さ2の葉が最短 | +| 最倧制玄 | ノヌド数 `10^5` | — | TLE・MLE が起きないこず | + +> 📖 **このセクションで登堎した甚語** +> +> - **゚ッゞケヌス**空のツリヌ・ノヌド1぀・盎線状の朚など、境界的な条件のこず +> - **RecursionError**再垰の呌び出し回数が `sys.getrecursionlimit()`デフォルト1000を超えたずきに発生する゚ラヌ +> - **TLETime Limit Exceeded**制限時間超過。蚈算量が倧きすぎるず発生する +> - **MLEMemory Limit Exceeded**メモリ制限超過。倧きなデヌタ構造を持ちすぎるず発生する +> - **フォヌルバック**「本来は到達しないが念のため曞いおおく凊理」。pylance の型チェックを通すためにも必芁 + +--- + +## たずめ + +| 芳点 | 内容 | +| --------------------- | ------------------------------------------------------------------------ | +| **問題の本質** | 根から最も近い葉たでの最短ノヌド数 | +| **最倧の眠** | 片方の子が `None` のノヌドは「葉」ではない | +| **採甚手法** | BFS`collections.deque` で O(1) popleft | +| **時間蚈算量** | O(n)最悪ケヌスで党ノヌド探玢 | +| **空間蚈算量** | O(w)キュヌの最倧サむズは朚の最倧幅 | +| **Python のポむント** | `list.pop(0)` ではなく `deque.popleft()` を䜿うこずで O(n) → O(1) に改善 | diff --git a/Algorithm/BinaryTree/leetcode/111. Minimum Depth of Binary Tree/claude sonnet 4.6 adaptive/Minimum_Depth_of_Binary_Tree_Typescript.md b/Algorithm/BinaryTree/leetcode/111. Minimum Depth of Binary Tree/claude sonnet 4.6 adaptive/Minimum_Depth_of_Binary_Tree_Typescript.md new file mode 100644 index 0000000..309204b --- /dev/null +++ b/Algorithm/BinaryTree/leetcode/111. Minimum Depth of Binary Tree/claude sonnet 4.6 adaptive/Minimum_Depth_of_Binary_Tree_Typescript.md @@ -0,0 +1,387 @@ +> 🎯 **[algo-beginner スキル発火]** +> 蚀語/カテゎリ: TypeScript +> 適甚ルヌルセット: 共通5ルヌル + TS固有5ルヌル +> 参照ファむル: references/common.md + references/typescript.md + +--- + +# 🌳 Minimum Depth of Binary Tree — 完党解説 + +--- + +## 1. 問題の分析 + +> 💡 **この問題を䞀蚀で蚀うず**「朚の根rootから葉leafたでの最短の道のりを求める問題」です。ただし **重倧な眠** がありたす。 + +--- + +### ⚠ 初孊者が必ずハマる眠「葉ノヌド」の定矩 + +「最短距離だから `Math.min(巊の深さ, 右の深さ)` でよいのでは」ず思うかもしれたせん。ずころが**それは間違いです**。 + +**葉ノヌドleaf nodeずは「巊も右も子どもを持たないノヌド」**のこずです。片方だけ子がある堎合は、葉ではありたせん。 + +``` +Example 2: root = [2,null,3,null,4,null,5,null,6] + + 2 + \ + 3 + \ + 4 + \ + 5 + \ + 6 ← ここが唯䞀の葉ノヌド +``` + +もし単玔に `Math.min(å·Š=0, 右=5)` = `0` を返しおしたうず、**巊の子がいないdepth=0が「葉」ず誀解されお答えが間違いたす**。巊の子が `null` のずきは、その方向は無効ずしお無芖し、右方向だけを蟿らなければなりたせん。 + +--- + +### 競技プログラミング芖点での分析 + +- **BFS幅優先探玢** が最適。根から局レベルごずに探玢し、**最初に葉に圓たった瞬間に即終了**できるため、最短ケヌスで非垞に高速 +- 深く偏った朚䟋2のような盎線状でも、DFSは党ノヌド走砎が必芁だが、BFSも最悪ケヌスでは同様になる +- ノヌド数の䞊限が `10^5` なので、O(n) であれば十分 + +### 業務開発芖点での分析 + +- 型安党性`TreeNode | null` の Union型2぀の可胜性を `|` で衚す型を正しく扱うこずが重芁 +- 再垰的DFSは実装が盎感的で保守しやすいが、深い朚でスタックオヌバヌフロヌ呌び出し回数が深くなりすぎおメモリが溢れるこずのリスクがある +- BFSはキュヌ埅ち行列を䜿うため、メモリ消費が明瀺的で制埡しやすい + +### TypeScript特有の考慮点 + +- `TreeNode | null` ずいう **Union型**で null安党性`null`によるクラッシュを防ぐ仕組みを衚珟できる +- `!` 非null アサヌション`queue.shift()!` のように、絶察にnullでないずコンパむラに䌝える蚘号はなるべく避け、明瀺的チェックを優先する + +> 📖 **このセクションで登堎した甚語** +> +> - **葉ノヌドleaf node**巊も右も子どもがないノヌド。朚の末端 +> - **BFSBreadth-First Search / 幅優先探玢**朚や図グラフを「深さの浅い順」に探玢する方法。階局ごずに暪に広がりながら探す +> - **DFSDepth-First Search / 深さ優先探玢**朚を「根から葉たで䞀本道を掘り進んで」探玢する方法。再垰で実装されるこずが倚い +> - **Union型**`A | B` のように耇数の型のどちらかである可胜性を衚すTypeScript固有の型衚蚘 + +--- + +## 2. アルゎリズムアプロヌチ比范 + +> 💡 同じ問題でも解き方は耇数ありたす。「速さ時間蚈算量」「メモリ空間蚈算量」「TypeScriptずの盞性」の芳点で比べお最適なものを遞びたす。 + +| アプロヌチ | 時間蚈算量 | 空間蚈算量 | TS実装コスト | 型安党性 | 可読性 | 備考 | +| --------------------------- | ------------------ | ---------- | ------------ | -------- | ------ | ---------------------------- | +| **BFS幅優先探玢** | O(n) ※早期終了あり | O(w)※1 | äž­ | 高 | 高 | 最初の葉で即終了できる最速解 | +| DFS 再垰Recursive | O(n) | O(h)※2 | 䜎 | 高 | 最高 | 偏った朚でスタック溢れリスク | +| DFS 反埩Iterative Stack | O(n) | O(n) | äž­ | 高 | äž­ | スタック溢れを回避できる | + +※1 `w` = 朚の最倧幅1レベルに存圚する最倧ノヌド数。完党二分朚では O(n/2) +※2 `h` = 朚の高さ根から最も深い葉たで。最悪 O(n)、平均 O(log n) + +> 💡 **Big-O蚘法の読み方**初孊者向け +> +> - `O(1)`入力の倧きさに関わらず、垞に䞀定の時間・メモリで枈む +> - `O(n)`ノヌド数が2倍になるず、凊理も玄2倍になる +> - `O(h)`朚の高さに比䟋。バランスの取れた朚なら `O(log n)` ず同等 + +> 📖 **このセクションで登堎した甚語** +> +> - **時間蚈算量**入力の倧きさに察しお凊理にかかる手間がどう増えるかの目安 +> - **空間蚈算量**凊理䞭に䜿うメモリ量がどう増えるかの目安 +> - **スタックオヌバヌフロヌ**再垰の呌び出しが深くなりすぎおメモリが溢れる゚ラヌ + +--- + +## 3. 遞択したアルゎリズムず理由 + +- **遞択したアプロヌチ**: **BFS幅優先探玢** + +- **理由**: + - 「最短」を求める問題では、「浅いレベルから順に探す BFS」が自然に䞀臎する。DFSは党おの葉を確認しおから比范するのに察し、**BFSは最初の葉を芋぀けた瞬間に確実に最小深さず蚀える** + - 䟋2のような盎線状の朚でも DFS再垰は O(n) のスタックを消費するが、BFS はキュヌで管理するためスタックオヌバヌフロヌが起きない + - TypeScript では配列をキュヌずしお䜿う実装がシンプルで型安党に曞きやすい + +- **TypeScript特有の最適化ポむント**: + - タプル型耇数の異なる型の倀を䞀組にたずめた配列の型`[TreeNode, number]` でノヌドず深さをペアずしお管理し、型安党にキュヌを衚珟 + - `null` チェックを TypeScript の型システムが匷制するため、葉刀定の挏れをコンパむル時に防げる + +> 📖 **このセクションで登堎した甚語** +> +> - **キュヌQueue**「先に入れたものを先に取り出す」デヌタ構造。「ファストフヌドの行列」ず同じむメヌゞ +> - **タプル型**`[string, number]` のように、芁玠の数ず各芁玠の型が固定された配列の型 +> - **コンパむル時**TypeScriptコヌドをJavaScriptに倉換する段階。ここで゚ラヌを怜出できるず実行時バグを防げる + +--- + +## 4. 実装コヌド + +> 💡 **コヌド党䜓の骚栌**先に構造を把握しおからコヌドを読みたしょう +> +> 1. **根が null なら 0 を返す**空の朚の特別ケヌス +> 2. **BFS 甚のキュヌに根ノヌドず深さ1を入れお開始** +> 3. **キュヌから取り出し → 葉なら即 return、子があればキュヌに远加** +> 4. **念のため党ノヌド探玢しおも葉がなければ 0 を返す** + +### 🏆 最終解答LeetCode 提出フォヌマット + +```typescript +// Runtime 1 ms +// Beats 84.75% +// Memory 94.50 MB +// Beats 56.90% + +function minDepth(root: TreeNode | null): number { + // ──────────────────────────────────────────────── + // â–Œ ケヌス1朚が空根がnullなら深さは0 + // nullチェックをここで行うこずで、埌続の凊理で + // 「rootが絶察に存圚する」ず安党に仮定できる + // ──────────────────────────────────────────────── + if (root === null) return 0; + + // ──────────────────────────────────────────────── + // â–Œ BFS甚のキュヌを初期化する + // タプル型 [TreeNode, number] = [ノヌド, 珟圚の深さ] + // 最初は根ノヌドを深さ1ずしお投入する + // なぜ1か根ノヌド自䜓が1番目のノヌドだから + // ──────────────────────────────────────────────── + const queue: Array<[TreeNode, number]> = [[root, 1]]; + + // ──────────────────────────────────────────────── + // â–Œ キュヌが空になるたでルヌプ= 党ノヌドを探玢 + // 葉が芋぀かった瞬間に return するので + // 通垞はキュヌが空になる前に終了する + // ──────────────────────────────────────────────── + while (queue.length > 0) { + // キュヌの先頭からノヌドず深さを取り出す + // shift() は配列の先頭芁玠を取り出す操䜜BFSの本質 + // 「! 」は「shift()の結果がundefinedでない」ずコンパむラに保蚌するための蚘号 + // ※ while条件 queue.length > 0 で空でないこずを確認枈みなので安党 + const [node, depth] = queue.shift()!; + + // ──────────────────────────────────────────── + // â–Œ 葉ノヌドの刀定巊も右も子がない = 葉 + // BFSは浅い順に探玢するため、最初に芋぀かった + // 葉が必ず最小深さを持぀ → 即座にreturnできる + // ──────────────────────────────────────────── + if (node.left === null && node.right === null) { + return depth; // 🎯 最短深さが確定 + } + + // ──────────────────────────────────────────── + // â–Œ 巊の子がある堎合キュヌに远加深さを+1 + // null チェックを先に行うこずで、 + // 存圚しない子を远加する無駄を防ぐ + // ──────────────────────────────────────────── + if (node.left !== null) { + queue.push([node.left, depth + 1]); + } + + // ──────────────────────────────────────────── + // â–Œ 右の子がある堎合同様にキュヌに远加 + // ──────────────────────────────────────────── + if (node.right !== null) { + queue.push([node.right, depth + 1]); + } + } + + // ──────────────────────────────────────────────── + // â–Œ ここには通垞到達しない根がnullでない有効な朚なら + // 必ずどこかに葉が存圚するため + // TypeScriptのコンパむラを満足させるため関数が + // 必ず倀を返すこずを保蚌するために蚘述する + // ──────────────────────────────────────────────── + return 0; +} +``` + +--- + +### 🔍 動䜜トレヌス2぀の䟋で倉数がどう倉わるか + +#### Example 1`root = [3,9,20,null,null,15,7]` + +``` + 3 ← 深さ 1 + / \ + 9 20 ← 深さ 2 + / \ + 15 7 ← 深さ 3 +``` + +``` +初期状態: + queue = [ [Node(3), 1] ] + +─── ルヌプ1回目 ─── + 取り出し: [Node(3), depth=1] + Node(3).left = Node(9) → null ではない + Node(3).right = Node(20) → null ではない + → 葉ではない + queue に远加: [Node(9), 2], [Node(20), 2] + queue = [ [Node(9), 2], [Node(20), 2] ] + +─── ルヌプ2回目 ─── + 取り出し: [Node(9), depth=2] + Node(9).left = null + Node(9).right = null + → 🎯 䞡方 null = 葉ノヌド発芋 + return 2 ← 答え確定残りのキュヌは凊理䞍芁 +``` + +#### Example 2`root = [2,null,3,null,4,null,5,null,6]`盎線状の朚 + +``` + 2 ← 深さ 1 + \ + 3 ← 深さ 2 + \ + 4 ← 深さ 3 + \ + 5 ← 深さ 4 + \ + 6 ← 深さ 5唯䞀の葉 +``` + +``` +初期: queue = [ [Node(2), 1] ] + +ルヌプ1: Node(2) → left=null, right=Node(3) + → 葉でないleftがnullでもrightがあるため + → 眠leftがnullだからずいっお葉ず刀断しおはいけない + queue = [ [Node(3), 2] ] + +ルヌプ2: Node(3) → left=null, right=Node(4) + → 葉でない、queue = [ [Node(4), 3] ] + +ルヌプ3: Node(4) → left=null, right=Node(5) + → 葉でない、queue = [ [Node(5), 4] ] + +ルヌプ4: Node(5) → left=null, right=Node(6) + → 葉でない、queue = [ [Node(6), 5] ] + +ルヌプ5: Node(6) → left=null, right=null + → 🎯 葉ノヌド発芋 return 5 +``` + +--- + +### ✹ 参考DFS 再垰版可読性重芖・業務開発向け + +こちらも玹介したす。コヌドが非垞に短く盎感的ですが、**深い朚でスタックオヌバヌフロヌのリスク**がありたす。 + +> このコヌドの構造 +> +> 1. `null` なら 0 を返すベヌスケヌス +> 2. 巊だけある → 巊に進む右方向を無芖する +> 3. 右だけある → 右に進む巊方向を無芖する +> 4. 䞡方ある → 䞡方探玢し `Math.min` で小さい方を返す + +```typescript +function minDepth(root: TreeNode | null): number { + // ベヌスケヌス再垰の終了条件 + // 根が null なら深さ0。このチェックがないず + // null.left にアクセスしおクラッシュする + if (root === null) return 0; + + // ──────────────────────────────────────────────── + // â–Œ 重芁片方の子だけが null の堎合の凊理 + // 巊が null → 巊方向には葉がない → 右方向のみ探玢 + // 「null の方向の深さ = 0」を最小倀に䜿っおしたうず + // 誀っお0+1=1が最小倀になるバグになる + // ──────────────────────────────────────────────── + if (root.left === null) { + // 巊の子が存圚しない堎合右方向の最小深さ + 自分自身の1 + return 1 + minDepth(root.right); + } + if (root.right === null) { + // 右の子が存圚しない堎合巊方向の最小深さ + 自分自身の1 + return 1 + minDepth(root.left); + } + + // 䞡方の子が存圚する堎合 + // 巊右それぞれの最小深さを求め、小さい方 + 自分自身の1 + return 1 + Math.min(minDepth(root.left), minDepth(root.right)); +} +``` + +> 📖 **このセクションで登堎した甚語** +> +> - **`Array.shift()`**配列の先頭芁玠を取り出しおその倀を返す操䜜。BFSで「最初に远加したものを最初に凊理する」ために䜿う +> - **タプル型**`[TreeNode, number]` のように芁玠数ず各型が固定された配列の型JavaScriptには存圚せず、TypeScript固有の仕組み +> - **ベヌスケヌス**再垰関数の「これ以䞊深く朜らなくおよい」終了条件 +> - **`readonly`修食子**倉数を倉曎できないようにする TypeScript 固有の機胜。JavaScriptには盞圓する構文がなく、意図せぬ曞き換えをコンパむル時に防ぐ + +--- + +## 5. ビゞュアル解説BFS の動き--- + +## 6. TypeScript 固有の最適化芳点 + +### 型安党性の掻甚 + +**Union型共甚䜓型**による null 安党性の確保 + +```typescript +// JavaScriptにはない抂念型レベルでnullの可胜性を明瀺できる +// TreeNode | null → 「TreeNodeかnullのどちらかである」ず型で衚明 +// コンパむラが null チェックを匷制しおくれる + +// 🔎 JavaScriptなら実行時たで気付かないクラッシュする +const left = root.left.val; // root.left が null なら TypeError! + +// ✅ TypeScriptなら null チェックを忘れるずコンパむル゚ラヌになる +if (node.left !== null) { + queue.push([node.left, depth + 1]); // ここでは left が TreeNode ず確定 +} +``` + +**タプル型**でキュヌの芁玠を厳密に型定矩 + +```typescript +// JavaScriptにはない構文芁玠数ず各型が固定された配列の型 +// [TreeNode, number] → 「1番目はTreeNode、2番目はnumber」ず保蚌 +// [Node(3), 1] のように䜿うこずで、ノヌドず深さが垞にペアになる + +// 「as const」を䜿うずさらに型を絞り蟌めるconst assertionず呌ぶ +// ※ this problem doesn't need it, but good to know + +const queue: Array<[TreeNode, number]> = [[root, 1]]; +// ↑ ↑ +// ノヌド型 深さ数倀型 +// この型定矩により、誀っお [1, root] の順で入れるずコンパむル゚ラヌになる +``` + +### readonly ず Pure function玔粋関数 + +BFS 解法はすでに Pure function の性質を持っおいたす + +```typescript +// ✅ 入力の root を倉曎しおいない読むだけ +// ✅ 倖郚の倉数グロヌバル状態に䟝存しおいない +// ✅ 同じ root を入れれば必ず同じ深さが返っおくる + +function minDepth(root: TreeNode | null): number { + // root を倉曎する操䜜䟋root.val = 999は䞀切行っおいない + // → 副䜜甚がない = Pure function +} +``` + +> 📖 **このセクションで登堎した甚語** +> +> - **Union型共甚䜓型**`A | B` のように耇数の型のどちらかを衚す TypeScript 固有の型衚蚘。`TreeNode | null` は「TreeNodeかnullのどちらか」 +> - **タプル型**`[string, number]` のように芁玠数ず各芁玠の型が固定された配列の型。むンデックスで `[0]` がstring、`[1]` がnumberず保蚌される +> - **Pure function玔粋関数**同じ入力を䞎えるず必ず同じ出力を返し、倖郚の状態を倉えない関数。テストしやすく、バグが少ない +> - **const assertion**`as const` ず曞くこずで、倉数の型をリテラル型具䜓的な倀そのものに絞り蟌む TypeScript 固有の機胜 + +--- + +## たずめ + +| 芳点 | 内容 | +| ------------------ | -------------------------------------------------------------------- | +| **問題の本質** | 根から最も近い葉たおの最短距離 | +| **最倧の眠** | 片方の子が `null` のノヌドは「葉」ではない | +| **遞択解法** | BFS最初の葉 = 確実に最浅 | +| **時間蚈算量** | O(n) — 最悪ケヌスで党ノヌド探玢 | +| **空間蚈算量** | O(w) — キュヌの最倧サむズは朚の最倧幅 | +| **TypeScript貢献** | `TreeNode \| null` による null 安党 + タプル型でキュヌを型安党に管理 | diff --git a/Algorithm/BinaryTree/leetcode/111. Minimum Depth of Binary Tree/claude sonnet 4.6 adaptive/README.md b/Algorithm/BinaryTree/leetcode/111. Minimum Depth of Binary Tree/claude sonnet 4.6 adaptive/README.md new file mode 100644 index 0000000..080ecab --- /dev/null +++ b/Algorithm/BinaryTree/leetcode/111. Minimum Depth of Binary Tree/claude sonnet 4.6 adaptive/README.md @@ -0,0 +1,862 @@ +# Minimum Depth of Binary Tree — 根から最短で葉に到達する深さを求める + +> **LeetCode #111** · 難易床: Easy · カテゎリ: Tree / BFS + +--- + +## 目次 + +- [抂芁](#overview) +- [アルゎリズム芁点TL;DR](#tldr) +- [図解](#figures) +- [正しさのスケッチ](#correctness) +- [蚈算量](#complexity) +- [Python 実装](#impl) +- [CPython 最適化ポむント](#cpython) +- [゚ッゞケヌスず怜蚌芳点](#edgecases) +- [FAQ](#faq) + +--- + +

3. 抂芁

+ +> 💡 **䞀蚀で蚀うず**「朚の根rootから、最も近い"末端ノヌド葉"たでのノヌド数を数える問題」です。 + +### 問題の内容 + +二分朚各ノヌドが最倧2぀の子を持぀朚が䞎えられたす。 +根ノヌドツリヌの頂点から葉ノヌド巊右ずもに子がない末端のノヌドたで、 +最も短いパスをたどったずきの**ノヌドの個数**を返しおください。 + +### なぜこの問題が難しいのか + +䞀芋「巊右の深さを再垰で蚈算しお `min()` で小さい方を返せばよい」ず思えたす。 +ずころが **倧きな眠** がありたす。それは「片方の子が `None`存圚しないのノヌドは葉ではない」ずいう点です。 + +たずえば䞋の朚を考えおみたしょう。 + +``` + 2 + \ + 3 + \ + 4 + \ + 5 + \ + 6 ← 唯䞀の葉 +``` + +ノヌド `2` は巊の子が `None` ですが、右の子 `3` がありたす。 +単玔に `min(巊の深さ=0, 右の深さ=4)` を蚈算しおしたうず `0 + 1 = 1` ずいう誀答になりたす。 +正しい答えは `5`根から葉 `6` たでの 5 ノヌドです。 +**「片方が `None` のずきは、その方向を無芖しお有効な方向だけを探玢する」ずいう特別な凊理が必芁です。** + +### 制玄 + +| 項目 | 倀 | +| ---------- | ------------------------- | +| ノヌド数 | 0 以䞊 10^5 以䞋 | +| ノヌドの倀 | -1000 以䞊 1000 以䞋 | +| 空の朚 | ありえる`root = None` | + +> 📖 **この章で登堎した甚語** +> +> - **二分朚**各ノヌドが最倧 2 ぀の子巊・右を持぀朚構造のデヌタ +> - **根ノヌドroot**朚の頂点にある1぀のノヌド。入口ずなる +> - **葉ノヌドleaf**巊の子も右の子も持たないノヌド。朚の末端 +> - **パス**朚の䞊を根から葉たで蟿る経路。芪から子ぞ䞀方向にしか進めない +> - **制玄**入力ずしお䞎えられる倀の範囲や条件のこず + +--- + +

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

+ +> 💡 **TL;DRToo Long; Didn't Read**ずは「長くお党郚読めない人向けの短い芁玄」を意味したす。 +> ここではアルゎリズム党䜓の戊略を箇条曞きでたずめたす。 +> 「なんずなくこういう手順で解くんだな」ずいうむメヌゞを掎む章ずしお䜍眮づけおいたす。 + +### 戊略BFS幅優先探玢で根から局ごずに探す + +1. **BFS を遞ぶ理由**「最短」を求める問題には BFS が自然に合臎する。 + BFS は浅い局から順に探玢するため、**最初に葉を芋぀けた瞬間**、それが確実に最小深さです。 + DFS深さ優先探玢のように党葉を比范する必芁がなく、早期終了できたす。 + +2. **デヌタ構造`collections.deque`デックを䜿う** + キュヌ先に入れたものを先に取り出す「行列」のようなデヌタ構造ずしお `deque` を䜿いたす。 + `list` の先頭削陀`pop(0)`は O(n) のコストがかかりたすが、`deque.popleft()` は O(1) です。 + +3. **ノヌドず深さをセットで管理** + キュヌの各芁玠を `(ノヌド, 珟圚の深さ)` のタプルで持ちたす。 + 倖郚のカりンタ倉数を䜿わないので、コヌドがシンプルになりたす。 + +4. **葉ノヌドの刀定を正しく行う** + `node.left is None and node.right is None` の堎合だけが葉です。 + 片方が `None` でも、もう片方に子がいれば葉ではありたせん。 + +5. **蚈算量のたずめ** + - 時間蚈算量O(n) — 最悪ケヌスで党ノヌドを 1 回ず぀凊理する + - 空間蚈算量O(w) — w は朚の最倧幅キュヌに同時に入る最倧ノヌド数 + +> 📖 **この章で登堎した甚語** +> +> - **BFS幅優先探玢**朚を「浅い局から順に暪に広がりながら」探玢する方法。キュヌを䜿う +> - **DFS深さ優先探玢**朚を「根から葉たで深く䞀本道を掘り進んで」探玢する方法。再垰やスタックを䜿う +> - **dequeデック**前からも埌ろからも O(1) で出し入れできる「䞡端開きの箱」のようなデヌタ構造 +> - **タプル**耇数の倀を䞀組にたずめた倉曎䞍可のデヌタ。`(node, 1)` のように曞く +> - **早期終了**答えが確定した瞬間にルヌプを抜けるこず。無駄な凊理をスキップしお高速化できる + +--- + +

5. 図解

+ +> 💡 **Mermaid フロヌチャヌトの読み方** +> +> - **長方圢`[]`**䜕かの凊理を行うステップです +> - **ひし圢`{}`**条件を刀定する分岐点です。「Yes/No」「True/False」で次の矢印が倉わりたす +> - **矢印`-->`**凊理の流れを瀺したす。ラベルが付いおいるずきはその条件のずきに進みたす + +### フロヌチャヌト + +この図は `minDepth` 関数党䜓の凊理の流れを衚しおいたす。䞊から䞋ぞ読み進めおください。 +特に `LeafTest`葉刀定の郚分が、この問題の栞心です。 + +```mermaid +flowchart TD + Start[Start minDepth] --> NullCheck{root is None} + NullCheck -- Yes --> R0[Return 0] + NullCheck -- No --> Init[Init deque with root at depth 1] + Init --> Loop{queue not empty} + Loop -- No --> Fallback[Return 0 fallback] + Loop -- Yes --> Pop[popleft node and depth] + Pop --> LeafTest{left is None AND right is None} + LeafTest -- Yes --> Ret[Return depth] + LeafTest -- No --> LeftEx{left exists} + LeftEx -- Yes --> PushL[Append left child at depth plus 1] + LeftEx -- No --> RightEx{right exists} + PushL --> RightEx + RightEx -- Yes --> PushR[Append right child at depth plus 1] + RightEx -- No --> Loop + PushR --> Loop +``` + +**䞻芁なノヌドの意味** + +- `Start[Start minDepth]`関数の入口。`root` を受け取る +- `NullCheck{root is None}`空の朚かどうかを最初に確認する分岐゚ッゞケヌス凊理 +- `Init[Init deque...]`BFS 甚キュヌに根ノヌドず深さ 1 を入れお探玢を開始する +- `Loop{queue not empty}`キュヌにノヌドが残っおいる間ルヌプを続ける分岐 +- `Pop[popleft node and depth]`キュヌの先頭からノヌドず深さを取り出すBFS の栞心 +- `LeafTest{left is None AND right is None}`葉ノヌドかどうかを刀定する分岐この問題の眠がここ +- `Ret[Return depth]`葉が芋぀かったので最小深さを返す早期終了 +- `PushL / PushR`子ノヌドが存圚する堎合だけキュヌに远加する + +--- + +### デヌタフロヌ図 + +この図は「入力の朚構造がどのようにキュヌを通っお最終的な深さの数倀に倉換されるか」のデヌタの流れを衚しおいたす。 + +```mermaid +graph LR + subgraph Input + A[TreeNode root] + end + subgraph BFS_Queue + B[deque init] + C[popleft node depth] + D[is leaf check] + E[push children] + end + subgraph Output + F[min depth int] + end + A --> B + B --> C + C --> D + D -- leaf found --> F + D -- not leaf --> E + E --> C +``` + +**䞻芁な流れの説明** + +- `A → B`根ノヌドをキュヌに投入し BFS を開始する +- `B → C`キュヌから先頭芁玠を取り出すpopleft +- `C → D`取り出したノヌドが葉かどうかを刀定する +- `D -- leaf found → F`葉なら即座に深さを返す早期終了 +- `D -- not leaf → E`葉でなければ子をキュヌに远加しお探玢を継続する +- `E → C`ルヌプ次のノヌドを取り出す + +--- + +### 代衚䟋でのトレヌス + +#### Example 1`root = [3, 9, 20, null, null, 15, 7]` → 期埅倀: `2` + +``` +朚の圢状: + 3 ← 深さ 1 + / \ + 9 20 ← 深さ 2 + / \ + 15 7 ← 深さ 3 + +Step 0: キュヌ初期化 + queue = deque([ (Node(val=3), depth=1) ]) + +Step 1: popleft → (Node(3), depth=1) + Node(3).left = Node(9) → None ではない + Node(3).right = Node(20) → None ではない + → LeafTest: False䞡方に子がいる + → PushL: queue に (Node(9), depth=2) を远加 + → PushR: queue に (Node(20), depth=2) を远加 + queue = deque([ (Node(9),2), (Node(20),2) ]) + +Step 2: popleft → (Node(9), depth=2) + Node(9).left = None ← None + Node(9).right = None ← None + → LeafTest: True䞡方 None = 葉ノヌド + → Return 2 ← 🎯 最小深さ確定残りのキュヌは凊理䞍芁 + +Answer: 2 ✅ +``` + +#### Example 2`root = [2, null, 3, null, 4, null, 5, null, 6]` → 期埅倀: `5` + +``` +朚の圢状: + 2 ← 深さ 1巊の子が null + \ + 3 ← 深さ 2 + \ + 4 ← 深さ 3 + \ + 5 ← 深さ 4 + \ + 6 ← 深さ 5唯䞀の葉 + +Step 0: キュヌ初期化 + queue = deque([ (Node(2), depth=1) ]) + +Step 1: popleft → (Node(2), depth=1) + Node(2).left = None ← None + Node(2).right = Node(3) ← None ではない + → LeafTest: Falseright に子がいる → 葉ではない + ⚠ 眠: left が None でも right があれば葉でないこずに泚意 + → PushL: スキップleft は None なので远加しない + → PushR: queue に (Node(3), depth=2) を远加 + queue = deque([ (Node(3),2) ]) + +Step 2〜5: 同様に Node(3)→Node(4)→Node(5) を凊理 + 各ノヌドの right のみキュヌに远加 + queue の状態: + Step 2埌: deque([ (Node(4),3) ]) + Step 3埌: deque([ (Node(5),4) ]) + Step 4埌: deque([ (Node(6),5) ]) + +Step 5: popleft → (Node(6), depth=5) + Node(6).left = None ← None + Node(6).right = None ← None + → LeafTest: True䞡方 None = 葉ノヌド + → Return 5 ← 🎯 最小深さ確定 + +Answer: 5 ✅ +``` + +> 📖 **この章で登堎した甚語** +> +> - **フロヌチャヌト**凊理の手順を図圢ず矢印で衚したもの。ひし圢=条件分岐、長方圢=凊理ステップ +> - **デヌタフロヌ図**デヌタがどのように倉換・移動するかを瀺す図。凊理の手順ではなく「デヌタの倉化」に着目する +> - **トレヌス**具䜓的な入力を䜿っおアルゎリズムの各ステップで倉数がどう倉わるかを远うこず + +--- + +

6. 正しさのスケッチ

+ +> 💡 **「正しさのスケッチ」ずは**アルゎリズムが垞に正しい答えを返せる根拠を敎理したものです。 +> 厳密な数孊的蚌明ではなく「なぜ正しいず蚀えるのか」の盎感的な説明です。 + +### 䞍倉条件ルヌプ䞭ずっず成り立぀べき条件 + +**「キュヌに入っおいるノヌドは、その深さが正しく蚘録されおいる」** + +- キュヌに最初に入れる `(root, 1)` は根ノヌドの深さ 1 で正しい +- 子ノヌドを远加するずき `depth + 1` ずするのは、「芪より 1 深い䜍眮にある」ずいう朚の定矩から正しい +- したがっお、ルヌプを䜕回繰り返しおも「キュヌ内の各芁玠のノヌドず深さの組み合わせ」は垞に正しい + +### 網矅性すべおのケヌスを凊理できおいるか + +BFS は同じ局のノヌドをすべおキュヌに入れおから次の局に進みたす。 +これにより「深さ 1 のノヌド → 深さ 2 のノヌド → ...」ず順番に凊理されたす。 +あるノヌドを「スキップ」するこずはないため、党おのノヌドを1回ず぀凊理したす。 + +> **ただし**、葉が芋぀かった時点で即 `return` するため、残りのノヌドは凊理されたせん。 +> これは問題ありたせん。なぜなら BFS の性質䞊、**最初に芋぀かった葉が確実に最小深さの葉**だからです。 + +### 基底条件終了条件 + +二重の終了条件がありたす + +1. **`root is None`**空の朚は葉ぞの道がないため深さ 0 を返す。この凊理がないず `None.left` でクラッシュする +2. **`node.left is None and node.right is None`**葉ノヌドを芋぀けたら即 `return`。BFS は浅い順に凊理するので最初の葉 = 最小深さ + +### 終了性必ず有限ステップで終わるか + +- ノヌド数は有限最倧 10^5 +- 各ノヌドは䞀床だけキュヌに远加される芪から子ぞの䞀方向 +- したがっおルヌプは最倧でもノヌド数回で終了する + +> 📖 **この章で登堎した甚語** +> +> - **䞍倉条件ルヌプ䞍倉匏**アルゎリズムが正しく動くために、凊理䞭ずっず成り立ち続けるべき条件 +> - **網矅性**すべおのケヌスをもれなく凊理できおいるずいう保蚌 +> - **基底条件**再垰やルヌプの終了条件。これがないず無限ルヌプ/クラッシュになる +> - **終了性**アルゎリズムが必ず有限ステップで終わるずいう保蚌 + +--- + +

7. 蚈算量

+ +> 💡 **蚈算量ずは**「入力が倧きくなるに぀れお、凊理にかかる時間・メモリがどう増えるか」の目安です。 +> Big-O 蚘法O(n) のような曞き方を䜿っお衚したす。 + +| 蚘法 | 意味 | 盎感的なむメヌゞ | +| ---------- | ---------------------- | ------------------------------ | +| O(1) | 入力サむズによらず䞀定 | 蟞曞で盎接ペヌゞを開く | +| O(n) | 入力に比䟋しお増加 | リストを端から順に読む | +| O(n log n) | n よりやや速く増加 | 蟞曞を二分探玢で匕く × n 回 | +| O(n²) | 入力の 2 乗で増加 | 党ペアを総圓たりで確認する | +| O(w) | 朚の最倧幅に比䟋 | その局に存圚するノヌド数に䟝存 | + +### この問題の蚈算量 + +| 芳点 | 蚈算量 | 説明 | +| -------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------ | +| **時間蚈算量** | O(n) | 党ノヌド数を n ずするず、各ノヌドを最倧 1 回だけキュヌから取り出す。葉が芋぀かれば早期終了するため、平均的にはさらに速い | +| **空間蚈算量** | O(w) | w は朚の最倧幅1 ぀の局に存圚する最倧ノヌド数。キュヌには同じ局のノヌドが同時に入るため、キュヌサむズの最倧倀は朚の最倧幅に等しい | + +### 最悪ケヌスでの空間蚈算量 + +- **完党二分朚**バランスの取れた朚最䞋局のノヌド数は n/2 個なので **O(n)** +- **盎線状の朚**䞀方向にのみ䌞びる朚垞に 1 ノヌドず぀キュヌに入るため **O(1)** + +### DFS再垰ずの比范 + +| 手法 | 時間蚈算量 | 空間蚈算量 | 備考 | +| --------------- | ---------- | ---------- | -------------------------------------------- | +| **BFS採甚** | O(n) | O(w) | 早期終了あり。葉が浅い堎合に高速 | +| DFS再垰 | O(n) | O(h) | h = 朚の高さ。盎線状の朚で再垰制限リスクあり | +| DFS反埩 | O(n) | O(h) | スタックオヌバヌフロヌを回避できる | + +> ※ h = 朚の高さ最悪 O(n)、完党二分朚では O(log n) +> 📖 **この章で登堎した甚語** +> +> - **時間蚈算量**入力の倧きさに察しお凊理にかかる手間がどう増えるかの目安 +> - **空間蚈算量**凊理䞭に䜿うメモリ量がどう増えるかの目安 +> - **朚の幅w**ある 1 ぀の局に存圚するノヌドの個数。BFS のキュヌサむズはこれに比䟋する +> - **朚の高さh**根から最も深い葉たでのノヌド数。DFS の再垰深床はこれに比䟋する +> - **早期終了**答えが確定した瞬間に凊理を打ち切るこず。平均的な実行時間を短瞮できる + +--- + +

8. Python 実装

+ +> 💡 **コヌドを読む前に実装の党䜓的な骚栌** +> +> 1. `from __future__ import annotations` で型ヒントの前方参照自己参照を有効にする +> 2. `TreeNode` のフォヌルバック定矩を `try/except NameError` で甚意するLeetCode 環境では䞍芁 +> 3. `root is None` の゚ッゞケヌスを最初に凊理する +> 4. `deque` でキュヌを初期化し、根ノヌドず深さ 1 を入れる +> 5. BFS ルヌプで `popleft()` → 葉刀定 → 子をキュヌに远加 を繰り返す +> 6. 最初に葉を芋぀けた時点で `return depth`早期終了 + +```python +from __future__ import annotations +# 型ヒントの前方参照を文字列ずしお遅延評䟡するTreeNode が自分自身を参照するため + +from collections import deque +# deque: popleft() が O(1) のキュヌ甚デヌタ構造。list.pop(0) は O(n) なので䜿わない + +from typing import Optional, TYPE_CHECKING +# Optional[X]: X か None のどちらかであるこずを衚す型ヒント + +# ────────────────────────────────────────────────────────────────── +# TreeNode の定矩 +# +# LeetCode 環境では TreeNode が自動的に定矩されおいる。 +# ロヌカル実行テストや IDEでは NameError が発生するため、 +# try/except でフォヌルバック定矩を甚意しおおく。 +# +# if TYPE_CHECKING: ブロックは pylance型チェッカヌだけが読むブロックで、 +# 実行時には評䟡されない。pylance に正確な型情報を䌝えるために䜿う。 +# ────────────────────────────────────────────────────────────────── +if TYPE_CHECKING: + # pylance 向けの型スタブ実行時には読たれない + 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: ... + +try: + TreeNode # noqa: F821 LeetCode 環境で定矩枈みかチェック +except NameError: + class TreeNode: # type: ignore[no-redef] + """ + ロヌカル実行甚の最小定矩。 + __slots__ を䜿うこずでむンスタンスごずの蟞曞䜜成を避け、 + メモリを節玄する。 + """ + __slots__ = ("val", "left", "right") + + def __init__( + self, + val: int = 0, + left: Optional[TreeNode] = None, + right: Optional[TreeNode] = None, + ) -> None: + self.val: int = val + self.left: Optional[TreeNode] = left + self.right: Optional[TreeNode] = right + + +class Solution: + def minDepth(self, root: Optional[TreeNode]) -> int: + """ + 二分朚の最小深さを BFS幅優先探玢で求める。 + + 最小深さずは「根から最も近い葉ノヌドたでのノヌド数」のこず。 + 葉ノヌドずは巊右どちらにも子を持たないノヌドを指す。 + + Args: + root: 二分朚の根ノヌド。None の堎合は空の朚を衚す。 + + Returns: + 最小深さ敎数。空の朚の堎合は 0 を返す。 + + Time Complexity: O(n) — 最悪ケヌスで n 個のノヌドを 1 回ず぀凊理する + Space Complexity: O(w) — w はキュヌの最倧サむズ朚の最倧幅 + """ + # ──────────────────────────────────────────────────────────── + # ゚ッゞケヌス: 空の朚root が None + # 根がなければ葉ぞの道も存圚しないため、深さは 0 を返す。 + # ここでチェックしないず、次行の queue.append((root, 1)) で + # None をキュヌに入れおしたい、埌で node.left にアクセスする際 + # AttributeError が発生する。 + # ──────────────────────────────────────────────────────────── + if root is None: + return 0 + + # ──────────────────────────────────────────────────────────── + # BFS 甚キュヌの初期化 + # + # なぜ list ではなく deque を䜿うのか + # list.pop(0) は O(n) → 先頭削陀のたびに党芁玠を 1 ぀巊にずらす + # deque.popleft() は O(1) → ポむンタを動かすだけで完結する + # ノヌド数が最倧 10^5 の堎合、この差は無芖できない + # + # キュヌの各芁玠は (ノヌド, 珟圚の深さ) のタプル。 + # 深さを倖郚のカりンタで管理せず、ノヌドず䞀緒に持ち運ぶこずで + # バグが入り蟌む䜙地を枛らしおいる。 + # ──────────────────────────────────────────────────────────── + queue: deque[tuple[TreeNode, int]] = deque() + queue.append((root, 1)) # 根ノヌドの深さは 1 + + # ──────────────────────────────────────────────────────────── + # BFS メむンルヌプ + # キュヌが空になるたで= 党ノヌドを凊理し終えるたで繰り返す + # ──────────────────────────────────────────────────────────── + while queue: + # 先頭から取り出すFIFO: 先に入れたものを先に取り出す + # popleft() は O(1) の操䜜deque を䜿う䞻な理由 + node, depth = queue.popleft() + + # ────────────────────────────────────────────────────── + # 葉ノヌド刀定 + # + # 葉の条件: 巊の子も右の子も None であるこず + # ※ 片方だけ None のノヌドは葉ではない重芁な眠 + # + # BFS は浅い局から順に凊理するため、 + # 最初に葉を芋぀けた時点でそれが確実に最小深さ。 + # 残りのキュヌを凊理する必芁はないので即 return する。 + # ────────────────────────────────────────────────────── + if node.left is None and node.right is None: + return depth # 🎯 最小深さ確定、即 return + + # ────────────────────────────────────────────────────── + # 子ノヌドをキュヌに远加する + # + # None の子を远加しないよう、必ず存圚チェックを先に行う。 + # None をキュヌに入れるず次のルヌプで node.left にアクセス + # できず AttributeError が発生する。 + # ────────────────────────────────────────────────────── + if node.left is not None: + # 巊の子が存圚する堎合のみキュヌに远加 + # 深さは芪の深さ + 11 段深くなるため + queue.append((node.left, depth + 1)) + + if node.right is not None: + # 右の子が存圚する堎合のみキュヌに远加巊ず同様 + queue.append((node.right, depth + 1)) + + # ──────────────────────────────────────────────────────────── + # フォヌルバック通垞はここに到達しない + # + # root が None でない有効な朚には必ず葉が存圚するため、 + # while ルヌプ内の return で必ず倀が返る。 + # pylance に「関数が必ず int を返す」こずを保蚌するために蚘述。 + # ──────────────────────────────────────────────────────────── + return 0 +``` + +--- + +### コヌドの動䜜トレヌス + +#### Example 1`root = [3, 9, 20, null, null, 15, 7]` + +``` +呌び出し: solution.minDepth(root) + root = Node(3) + + 1. if root is None → Falseroot は存圚する→ 通過 + 2. queue 初期化: deque([ (Node(3), 1) ]) + + === ルヌプ 1 回目 === + popleft → node=Node(3), depth=1 + 葉刀定: Node(3).left=Node(9) is None → False → 葉でない + PushL: Node(3).left=Node(9) is not None → queue.append((Node(9), 2)) + PushR: Node(3).right=Node(20) is not None → queue.append((Node(20), 2)) + queue = deque([ (Node(9),2), (Node(20),2) ]) + + === ルヌプ 2 回目 === + popleft → node=Node(9), depth=2 + 葉刀定: Node(9).left=None AND Node(9).right=None → True + → return 2 ← 🎯 確定 + +最終結果: 2 ✅ +``` + +#### Example 2`root = [2, null, 3, null, 4, null, 5, null, 6]` + +``` + 1. if root is None → False → 通過 + 2. queue 初期化: deque([ (Node(2), 1) ]) + + === ルヌプ 1 回目 === + popleft → node=Node(2), depth=1 + 葉刀定: Node(2).left=None, Node(2).right=Node(3) + → left は None だが right は None でない → False葉でない眠 + PushL: Node(2).left=None → スキップ + PushR: Node(2).right=Node(3) is not None → queue.append((Node(3), 2)) + queue = deque([ (Node(3),2) ]) + + === ルヌプ 2〜5 回目同様=== + Node(3)→queue.append((Node(4),3)) + Node(4)→queue.append((Node(5),4)) + Node(5)→queue.append((Node(6),5)) + + === ルヌプ 6 回目 === + popleft → node=Node(6), depth=5 + 葉刀定: Node(6).left=None AND Node(6).right=None → True + → return 5 ← 🎯 確定 + +最終結果: 5 ✅ +``` + +> 📖 **この章で登堎した甚語** +> +> - **`from __future__ import annotations`**型ヒントを文字列ずしお遅延評䟡するようにする宣蚀。`TreeNode` が自分自身を型ヒントで参照するずきに必芁 +> - **`TYPE_CHECKING`**実行時は `False`、pylance などの型チェッカヌ実行時は `True` になる定数。型スタブをこのブロックに曞くこずでランタむムコストを避けられる +> - **`Optional[TreeNode]`**`TreeNode` か `None` のどちらかであるこずを衚す型ヒント。pylance が `None` チェックを匷制しおくれる +> - **`__slots__`**クラスのむンスタンス倉数を固定するこずで、通垞の蟞曞の代わりに軜量な構造でメモリを節玄する仕組み +> - **フォヌルバック**「本来は到達しないが念のため曞いおおく凊理」。pylance に党パスで `int` を返すこずを蚌明するために必芁 + +--- + +

9. CPython 最適化ポむント

+ +> 💡 **この章では**同じ凊理でも Python の曞き方によっお速さが倉わる理由を説明したす。 +> 「最適化前 → 最適化埌 → なぜ速くなるか」の 3 点セットで解説したす。 + +### 最適化ポむント 1`list.pop(0)` を `deque.popleft()` に眮き換える + +BFS の実装でよく芋かける間違いが、`list` をキュヌずしお䜿うこずです。 + +```python +# ❌ 最適化前list を䜿ったキュヌ遅い +queue: list[tuple[TreeNode, int]] = [(root, 1)] +# ... +node, depth = queue.pop(0) # O(n): 党芁玠を巊に 1 ぀ず぀ずらす凊理が発生する + +# ✅ 最適化埌deque を䜿ったキュヌ速い +from collections import deque +queue: deque[tuple[TreeNode, int]] = deque([(root, 1)]) +# ... +node, depth = queue.popleft() # O(1): ポむンタを移動するだけで完結する +``` + +**なぜ速くなるのか** +Python の `list` は内郚的に連続したメモリ配列C蚀語の配列で実装されおいたす。 +先頭芁玠を削陀するず、残り党芁玠を 1 ぀巊にずらさなければならないため O(n) のコストがかかりたす。 +`deque` は双方向連結リストポむンタで繋がれた箱の連鎖で実装されおおり、 +先頭のポむンタを動かすだけで枈むため O(1) で削陀できたす。 + +ノヌド数が 10^5 の堎合、`pop(0)` を䜿うず最悪 O(n²) に劣化したすが、`popleft()` なら O(n) を保おたす。 + +--- + +### 最適化ポむント 2早期終了Early Returnを掻甚する + +BFS の利点は「最初に葉を芋぀けた瞬間に終了できる」こずです。 + +```python +# ✅ 葉を芋぀けた瞬間に return する早期終了 +if node.left is None and node.right is None: + return depth # ← ここで即終了。残りのキュヌは凊理しない +``` + +䟋えば完党二分朚の堎合、深さ k の葉を最初に芋぀けた時点で終了するため、 +より深い葉深さ k+1, k+2, ...の探玢を完党にスキップできたす。 + +--- + +### 最適化ポむント 3`is None` vs `== None` + +```python +# ❌ 最適化前遅い・pylance 譊告も出る +if node.left == None: + ... + +# ✅ 最適化埌速い・Pythonic +if node.left is None: + ... +``` + +**なぜ `is None` の方が速いのか** +`== None` は `__eq__` メ゜ッドを呌び出しお比范したすメ゜ッド呌び出しのオヌバヌヘッドあり。 +`is None` はオブゞェクトの IDメモリアドレスを盎接比范するため、より高速です。 +たた Python の `None` はシングルトンプログラム内で唯䞀のオブゞェクトなので `is` で正しく比范できたす。 + +--- + +### 最適化ポむント 4ノヌドず深さをタプルで䞀緒に管理する + +```python +# ❌ 最適化前倖郚のカりンタで深さを管理バグが入りやすい +queue = deque([root]) +depth = 0 +level_size = 1 +while queue: + depth += 1 + for _ in range(level_size): + node = queue.popleft() + if not node.left and not node.right: + return depth + ... + level_size = len(queue) + +# ✅ 最適化埌ノヌドず深さをタプルで䞀緒に持ち運ぶシンプル +queue: deque[tuple[TreeNode, int]] = deque([(root, 1)]) +while queue: + node, depth = queue.popleft() # 深さが垞にノヌドず䞀臎する + ... +``` + +タプルアンパック`node, depth = queue.popleft()`は CPython 内郚で最適化されおおり、 +蟞曞や別オブゞェクトを䜿うよりもメモリ効率が良く、高速です。 + +> 📖 **この章で登堎した甚語** +> +> - **連続したメモリ配列**芁玠がメモリ䞊に隙間なく䞊んだデヌタ構造。先頭削陀に O(n) かかる +> - **双方向連結リスト**各芁玠が前埌の芁玠ぞのポむンタを持぀デヌタ構造。先頭・末尟操䜜が O(1) +> - **シングルトン**プログラム内で同じ型のむンスタンスが 1 ぀しか存圚しないオブゞェクト。Python の `None`, `True`, `False` がこれにあたる +> - **タプルアンパック**`a, b = (1, 2)` のように、タプルの芁玠を耇数の倉数に同時に代入するこず +> - **O(n²) に劣化**入力が 2 倍になるず凊理が 4 倍になるこず。`pop(0)` を n 回繰り返すず合蚈 O(n²) になる + +--- + +

10. ゚ッゞケヌスず怜蚌芳点

+ +> 💡 **゚ッゞケヌスずは**「空のツリヌ・ノヌド 1 ぀・盎線状の朚」など、境界的な入力のこずです。 +> ゚ッゞケヌスを芋萜ずすず、普通のテストは通るのに特定の入力でだけバグが発生したす。 +> 各ケヌスに぀いお「なぜそのケヌスが問題になりうるか」を確認しおおきたしょう。 + +| # | ケヌス名 | 入力䟋 | 期埅倀 | なぜ問題になりうるか | +| --- | ------------- | -------------------------------- | ------ | --------------------------------------------------------------------------------------- | +| 1 | 空の朚 | `root = None` | `0` | `root.left` にアクセスするずクラッシュする。最初に `None` チェックが必芁 | +| 2 | ノヌドが 1 ぀ | `root = [1]` | `1` | 根自䜓が葉。`1 + min(left, right)` を䜿うアプロヌチでは深さ 0 を誀返华しがち | +| 3 | 巊のみ偏り朚 | `root = [1, 2]` | `2` | 右の子がないため右方向の深さを 0 ず誀解するず、`min(0+1, 2+1) = 1` ずいう誀答になる | +| 4 | 右のみ偏り朚 | `root = [1, null, 2]` | `2` | ケヌス 3 の巊右を入れ替えたもの。同様の眠がある | +| 5 | 盎線状の朚 | `root = [2,null,3,null,...,6]` | `5` | Example 2 が該圓。党ノヌドが右方向に䞀盎線で、葉は最深郚の 1 ぀だけ | +| 6 | 完党二分朚 | `root = [3,9,20,null,null,15,7]` | `2` | Example 1 が該圓。最浅の葉深さ 2を早期に発芋できるかが鍵 | +| 7 | 巊右完党察称 | `root = [1,2,2,3,3,3,3]` | `3` | どちら偎から探玢しおも同じ深さ。BFS は問題なく凊理できる | +| 8 | 最倧ノヌド数 | ノヌド数 10^5 の盎線状の朚 | `10^5` | `deque` を䜿わないず TLE制限時間超過になる。再垰 DFS では RecursionError が発生する | + +### ケヌス 3 の詳现「巊のみ偏り朚」の眠 + +``` +入力: root = [1, 2] +朚の圢状: + 1 ← 深さ 1 + / + 2 ← 深さ 2唯䞀の葉 + +間違ったアプロヌチmin を単玔に䜿う: + minDepth(root) = 1 + min(minDepth(left), minDepth(right)) + = 1 + min(minDepth(Node(2)), minDepth(None)) + = 1 + min(1, 0) ← 0 は「深さなし」ではなく誀り + = 1 ← ❌ 誀答 + +正しいアプロヌチBFS の堎合: + Step 1: popleft → Node(1), depth=1 + left=Node(2) (not None), right=None → 葉でない + → PushL: queue.append((Node(2), 2)) + → PushR: right は None なのでスキップ + Step 2: popleft → Node(2), depth=2 + left=None AND right=None → 葉 + → return 2 ← ✅ 正答 +``` + +> 📖 **この章で登堎した甚語** +> +> - **゚ッゞケヌス**空の朚・ノヌド 1 ぀・最倧サむズ入力など、境界的な条件の入力 +> - **TLETime Limit Exceeded**制限時間超過。O(n²) のアルゎリズムは倧きな入力でこれが発生する +> - **RecursionError**Python の再垰呌び出し回数がデフォルト制限1000 回を超えたずきの゚ラヌ。10^5 ノヌドの盎線状の朚で再垰 DFS を䜿うず発生する +> - **偏り朚偏向朚**䞀方向にのみ䌞びる、盎線に近い圢の朚。最悪ケヌスの代衚䟋 + +--- + +

11. FAQ

+ +> 💡 **FAQFrequently Asked Questions**初孊者が぀たずきやすいポむントをたずめた Q&A です。 + +--- + +**Q1. なぜ `list.pop(0)` ではなく `deque.popleft()` を䜿うのですか** + +**結論**`list.pop(0)` は O(n) のコストがかかり、ノヌド数が倚いず著しく遅くなるからです。 + +**理由**Python の `list` は内郚的に連続したメモリ配列で実装されおいたす。 +先頭芁玠を削陀するず、残り党芁玠を 1 ぀ず぀巊にずらさなければなりたせん。 +䟋えばノヌドが 1000 個あれば、1 回の `pop(0)` で最倧 999 個の芁玠を移動させたす。 +これを 1000 回繰り返すず合蚈 O(n²) になりたす。 + +**補足具䜓䟋** + +```python +# ❌ list を䜿った堎合ノヌド数 n で O(n²) +q = [1, 2, 3, 4, 5] +q.pop(0) # → [2, 3, 4, 5] ← 内郚で 4 芁玠を巊にずらした + +# ✅ deque を䜿った堎合ノヌド数 n で O(n) +from collections import deque +q = deque([1, 2, 3, 4, 5]) +q.popleft() # → deque([2, 3, 4, 5]) ← ポむンタを動かすだけ芁玠は移動しない +``` + +--- + +**Q2. なぜ片方の子が `None` でも葉にならないのですか** + +**結論**葉の定矩が「巊右どちらにも子がないノヌド」であるからです。 +片方だけ `None` の堎合は、もう片方の方向に探玢を続ける必芁がありたす。 + +**理由**もし「片方が `None` なら葉扱い」にしおしたうず、 +Example 2 の `Node(2)` のように「右の子はあるが巊の子はない」ノヌドを葉ず刀定しおしたい、 +深さ 1 ずいう誀答を返しおしたいたす。 + +**補足DFS 再垰の堎合の正しい曞き方** + +```python +def minDepth(self, root: Optional[TreeNode]) -> int: + if root is None: + return 0 + # 巊の子がない堎合 → 右方向のみ探玢 + if root.left is None: + return 1 + self.minDepth(root.right) + # 右の子がない堎合 → 巊方向のみ探玢 + if root.right is None: + return 1 + self.minDepth(root.left) + # 䞡方ある堎合 → 䞡方探玢しお小さい方 + return 1 + min(self.minDepth(root.left), self.minDepth(root.right)) +``` + +--- + +**Q3. DFS再垰ではダメなのですか BFS を遞ぶ理由は䜕ですか** + +**結論**DFS再垰も正しい答えを返したすが、2 ぀のリスクがありたす。 +BFS の方がこの問題の性質に自然に合臎し、より安党です。 + +**理由 1再垰深床の制限** +Python のデフォルト再垰深床制限は 1000 回です。 +盎線状の朚でノヌド数が 10^5 の堎合、DFS 再垰は `RecursionError` で倱敗したす。 +BFS はスタックを䜿わないため、この問題が発生したせん。 + +**理由 2「最短」問題に BFS が自然に合臎する** +DFS は党おの葉を探玢しおから `min()` で比范したす。 +BFS は浅い局から探玢するため、最初に葉を芋぀けた瞬間に終了できたす早期終了。 +完党二分朚のような「答えが浅い䜍眮にある」ケヌスでは BFS が倧幅に速いです。 + +**補足**`sys.setrecursionlimit()` で制限を増やす方法もありたすが、 +スタックオヌバヌフロヌOS レベルのクラッシュを匕き起こす可胜性があり掚奚されたせん。 + +--- + +**Q4. キュヌの芁玠を `(ノヌド, 深さ)` のタプルにする理由は䜕ですか** + +**結論**ノヌドず深さを垞にセットで管理するこずで、コヌドがシンプルになりバグが入りにくくなりたす。 + +**理由**別の実装ずしお「局ごずにルヌプを回しおカりンタを増やす」方法もありたす。 +しかしその堎合は「珟圚の局のサむズ」を別で管理する必芁があり、コヌドが耇雑になりたす。 +タプルでノヌドず深さを䞀緒に持ち運べば、どのノヌドを凊理しおも深さが垞に正確に分かりたす。 + +**補足別実装ずの比范** + +```python +# 別実装局のサむズを管理する方法耇雑 +while queue: + level_size = len(queue) # 珟圚の局のノヌド数 + depth += 1 + for _ in range(level_size): # 珟圚の局を党郚凊理しおから深さを増やす + node = queue.popleft() + ... + +# 採甚した実装タプルで管理シンプル +while queue: + node, depth = queue.popleft() # 深さは垞にノヌドず䞀臎 + ... +``` + +--- + +**Q5. フォヌルバックの `return 0` は本圓に必芁ですか** + +**結論**ロゞック的には到達したせんが、pylance型チェッカヌのために必芁です。 + +**理由**pylance は「関数の党コヌドパスで `int` が返るこずを保蚌できるか」を静的に確認したす。 +`while queue:` ブロックは「キュヌが空になれば通過する」可胜性があるず刀断されるため、 +ブロックの埌に `return` 文がないず「`None` を返す可胜性がある」ずいう型゚ラヌを報告したす。 +実際には `root is not None` であれば葉が必ず存圚するためここには到達したせんが、 +pylance を満足させるために `return 0` を蚘述したす。 + +> 📖 **この章で登堎した甚語** +> +> - **FAQ**Frequently Asked Questions の略。よくある質問ず回答のこず +> - **RecursionError**Python の再垰呌び出しがデフォルト䞊限1000 回を超えたずきの゚ラヌ +> - **スタックオヌバヌフロヌ**再垰呌び出しが深くなりすぎおメモリコヌルスタックが溢れるこず +> - **早期終了**答えが確定した瞬間に凊理を打ち切るこず。BFS で最初の葉を芋぀けた瞬間がこれにあたる +> - **静的型チェック**プログラムを実行せずにコヌドを読むだけで型の䞍敎合を怜出する手法。pylance がこれを担う + +--- + +_最終曎新CPython 3.11.10 / LeetCode #111 Minimum Depth of Binary Tree_ diff --git a/Algorithm/BinaryTree/leetcode/111. Minimum Depth of Binary Tree/claude sonnet 4.6 adaptive/README_react.html b/Algorithm/BinaryTree/leetcode/111. Minimum Depth of Binary Tree/claude sonnet 4.6 adaptive/README_react.html new file mode 100644 index 0000000..da5f8e2 --- /dev/null +++ b/Algorithm/BinaryTree/leetcode/111. Minimum Depth of Binary Tree/claude sonnet 4.6 adaptive/README_react.html @@ -0,0 +1,1776 @@ + + + + + + LeetCode 111 - Minimum Depth of Binary Tree | BFS解説 + + + + + + + + + + + +
+ + + + +
+

+ アルゎリズム抂芁 +

+ +
+

+ 💡 + この問題を䞀蚀で蚀うず「根ノヌドから最も近い葉ノヌドたでの最短経路のノヌド数を返す問題」 +

+

+ 「最小深さ」ずは、朚の根䞀番䞊から出発しお、最初に到達できる葉子を持たないノヌドたでのノヌド数のこずです。深さは根を1ずしお数えたす。葉ノヌドずは、巊の子も右の子もどちらも存圚しないノヌドのこずです。 +

+
+ +
+

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

+
    +
  • + 「片偎だけに子があるノヌド」が眠になる巊の子がない葉、ではありたせん。たずえば右の子だけを持぀ノヌドは葉ではなく、右ぞ続く経路がある「䞭間ノヌド」です。䟋2[2,null,3,null,4,null,5,null,6]がその兞型で、最小深さはなんず + 5 になりたす。 +
  • +
  • + DFS深さ優先では最短を保蚌できないDFS + は「葉に到達するたで䞀方向に朜り続ける」性質があるため、偶然最初に芋぀かった葉が最短ずは限りたせん。BFS + なら浅いノヌドから順番に調べるので、最初に芋぀かった葉が必ず最短です。 +
  • +
+
+ +
+
+
O(n)
+
時間蚈算量
+
+
+
O(w)
+
空間蚈算量 (w=最倧幅)
+
+
+
BFS
+
アルゎリズム
+
+
+
deque
+
䜿甚デヌタ構造
+
+
+ +
+
+

䟋1: 通垞の二分朚

+
+入力: root = [3,9,20,null,null,15,7]
+
+      3
+     / \
+    9  20
+       / \
+      15   7
+
+出力: 2
+

+ æ ¹(3)→巊の子(9) + の経路が長さ2で最短。ノヌド9は巊も右も子がない「葉」のため、深さ2が答えになりたす。 +

+
+
+

+ 䟋2: 䞀方向にだけ䌞びる朚 +

+
+入力: root = [2,null,3,null,4,null,5,null,6]
+
+2
+ \
+  3
+   \
+    4
+     \
+      5
+       \
+        6   ← 唯䞀の葉
+
+出力: 5
+

+ 右方向にのみ子があり、唯䞀の葉はノヌド6。葉たでの距離が5なのでその深さが答えです。 +

+
+
+
+ + +
+

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

+
+
+ + +
+

+ Python 実装 +

+ +
+

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

+
    +
  1. ゚ッゞケヌス凊理root が None空の朚なら即座に 0 を返す
  2. +
  3. BFS キュヌを初期化deque に (根ノヌド, 深さ=1) のペアを入れる
  4. +
  5. キュヌが空になるたで繰り返す浅い順にノヌドを䞀぀ず぀凊理する
  6. +
  7. + 葉ノヌドに到達したら深さを返すBFS の特性で、最初の葉が必ず最短経路 +
  8. +
+
+ +
from typing import Optional
+from collections import deque
+
+
+class Solution:
+    def minDepth(self, root: Optional[TreeNode]) -> int:
+        # ─────────────────────────────────────
+        # ゚ッゞケヌス: 空の朚 → 深さ 0 を返す
+        # 根がなければ「葉たでの道」自䜓が存圚しない
+        # ─────────────────────────────────────
+        if root is None:
+            return 0
+
+        # ─────────────────────────────────────
+        # BFS キュヌを初期化する
+        # deque の popleft() は O(1) ← list より効率的
+        # タプル (ノヌド, 珟圚の深さ) でペアを管理する
+        # ─────────────────────────────────────
+        queue: deque = deque()
+        queue.append((root, 1))   # 根ノヌドは深さ 1 からスタヌト
+
+        while queue:
+            # popleft() = FIFO先入れ先出し→ 浅い順に凊理
+            node, depth = queue.popleft()
+
+            # ─────────────────────────────────
+            # 葉ノヌド刀定: 巊も右も子がない = 葉
+            # BFS は浅い順なので、最初の葉 = 最小深さ
+            # ─────────────────────────────────
+            if node.left is None and node.right is None:
+                return depth      # 最小深さ確定
+
+            # 子ノヌドは存圚する堎合のみキュヌに远加
+            if node.left is not None:
+                queue.append((node.left,  depth + 1))
+            if node.right is not None:
+                queue.append((node.right, depth + 1))
+
+        return 0  # 有効な朚なら通垞ここに到達しない
+ +
+

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

+
+初期状態: queue = [(node=3, depth=1)]
+
+反埩 1: pop → (node=3, depth=1)
+   巊の子: 9 あり, 右の子: 20 あり → 葉ではない
+   → queue に (node=9, depth=2) ず (node=20, depth=2) を远加
+   → queue = [(node=9, depth=2), (node=20, depth=2)]
+
+反埩 2: pop → (node=9, depth=2)
+   巊の子: None, 右の子: None → 🌿 葉ノヌド発芋
+   → return 2   ✅ 答え: 2探玢終了
+
+※ node=20 はキュヌに残ったたたですが、葉を芋぀けた時点で即 return
+   するためこれ以䞊凊理は行われたせん。
+
+
+ + +
+

+ 凊理フロヌチャヌト +

+ +
+

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

+
+
+ + + + 楕円緑 開始・終了 +
+
+ + + + 四角青 凊理ステップ +
+
+ + + + ひし圢黄 条件分岐 +
+
+ 緑はい + 赀いいえ +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + 開始 + + + + + + + + + + root is None ? + + + 朚が空かどうか + + + + + はい + + + + + + + 0 を返す + + + return 0 + + + + + + + + いいえ + + + + + + + BFS キュヌを初期化 + + + queue = deque([(root, 1)]) + + + + + + + + + キュヌからノヌドを取り出す + + + node, depth = queue.popleft() + + + + + + + + + 葉ノヌド? + + + left==None and right==None + + + + + はい + + + + + + + depth を返す + + + return depth + + + + + + + + + + + + + + + + いいえ + + + + + + + 子ノヌドをキュヌに远加 + + + queue.append((child, depth + 1)) + + + + + + + + + ル + + + ヌ + + + プ + + + + + + 終了 + + +
+ +
+

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

+
    +
  1. + 「開始」→ root = TreeNode(3) なので None ではない → 「いいえ」の経路ぞ +
  2. +
  3. 「BFS キュヌ初期化」→ queue = [(node=3, depth=1)] にセット
  4. +
  5. 「キュヌから取出し」→ node=3, depth=1 を popleft で取り出す
  6. +
  7. + 「葉ノヌド?」→ node=3 の left=9, right=20 があるので「いいえ」→ + 子をキュヌに远加 +
  8. +
  9. + 「子をキュヌに远加」→ queue = [(node=9, depth=2), (node=20, depth=2)] + になりルヌプ +
  10. +
  11. 「キュヌから取出し」→ node=9, depth=2 を取り出す
  12. +
  13. + 「葉ノヌド?」→ node=9 の left=None, right=None → 「はい」→ depth=2 + を返す +
  14. +
  15. 「終了」→ 答え 2 を返しお凊理完了
  16. +
+
+ +

+ フロヌの芁点
+ BFS + はキュヌを䜿っお「浅いノヌドから順番に」凊理したす。ルヌプ玫の矢印は次のノヌドを凊理するためにキュヌぞ戻るこずを衚しおいたす。右偎の緑の線サむドラむンは「条件を満たしたので早期リタヌン」する経路です。root is None + のずきは 0 を、葉ノヌドを芋぀けたずきはそのずきの + depth + を即座に返したす。 +

+
+ + +
+

+ 蚈算量分析 +

+ +
+

+ 📖 Big-O 蚘法の読み方入力サむズ n が倧きくなるず凊理時間がどう倉わるか +

+
+
+
O(1)
+
+ 垞に䞀定
䟋蟞曞の盎接匕き +
+
+
+
O(n)
+
+ 入力に比䟋
䟋リストを1回走査 +
+
+
+
O(n log n)
+
+ n より少し倚い
䟋マヌゞ゜ヌト +
+
+
+
O(n²)
+
+ 入力の2乗
䟋二重ルヌプ総圓たり +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ 皮別 + + 蚘法 + + 倉数の意味 + + ケヌス +
+ 時間蚈算量 + + O(n) + + n = 朚のノヌド総数 + + 最悪ケヌス党ノヌド蚪問 +
+ 空間蚈算量 + + O(w) + + w = 朚の最倧幅1段のノヌド最倧数 + + 完党二分朚では O(n/2) ≈ O(n) +
+
+ +
+

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

+

+ 時間 O(n)最悪のケヌスでは、葉が最埌の1個で朚の最深郚にある状況です䟋2のような䞀方向に䌞びる朚。この堎合、党 + n ノヌドをキュヌから1回ず぀取り出しお凊理するため、凊理回数は n + に比䟋したす。ただし最良のケヌスは根ノヌド自䜓が葉n=1のずきで、即座に + O(1) で返りたす。

空間 O(w)キュヌには「同じ深さのノヌド」が同時に蓄積されたす。最もノヌドが密集する段= + 朚の最倧幅 wのずき、キュヌのサむズが最倧になりたす。完党二分朚の最䞋段では + w ≈ n/2 ずなり、事実䞊 O(n) ず等䟡です。 +

+
+
+ + +
+

+ 📖 甚語集 +

+

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

+
+
+ + ▶ BFS幅優先探玢 + +
+ Breadth-First Search + の略。朚やグラフを「根に近い順」「浅い階局から順番に」探玢するアルゎリズムです。「うずたきのように倖偎から内偎に向かっお広がる」むメヌゞに䟋えられたす。キュヌ埅ち行列を䜿っお実装し、最短経路の発芋に特に適しおいたす。察矩語は + DFS深さ優先探玢。 +
+
+ +
+ + ▶ dequeデク + +
+ double-ended queue䞡端キュヌの略。Python の + collections.deque + が提䟛したす。先頭ず末尟の䞡端から O(1) + の定数時間で芁玠の远加・取り出しができたす。通垞の + list の + pop(0) + は O(n) のコストがかかるため、BFS には deque の䜿甚が必須です。 +
+
+ +
+ + ▶ + 葉ノヌドリヌフノヌド + +
+ 巊の子も右の子も持たないノヌドのこずです。朚の末端に䜍眮したす。「葉」ずいう名前は、朚の葉っぱが枝の末端にあるこずに由来したす。刀定条件は + node.left is None and node.right is None + です。泚意点巊右どちらか䞀方の子しか持たないノヌドは葉ではありたせん。 +
+
+ +
+ + ▶ キュヌ埅ち行列/ + FIFO + +
+ FIFOFirst In, First Out = + 先入れ先出しの原則に埓うデヌタ構造です。コンビニのレゞ埅ちの列ず同じで、先に䞊んだ人が先に凊理されたす。BFS + では「浅いノヌドを先に凊理する」ために必須です。append() + で末尟に远加し、popleft() + で先頭から取り出したす。 +
+
+ +
+ + ▶ + 根ノヌドルヌトノヌド + +
+ 朚の最䞊䜍に䜍眮する唯䞀のノヌドです。芪ノヌドを持ちたせん。朚の探玢はここから開始したす。深さの数え方では、根ノヌドの深さを + 1 ずしお数えたす問題によっおは 0 から数えるこずもありたす。 +
+
+ +
+ + ▶ 時間蚈算量 / 空間蚈算量 + +
+ 時間蚈算量入力サむズ n + が増えたずきに、凊理ステップ数がどのくらい増えるかの指暙です。O(n) は「n + が2倍になるず凊理も玄2倍」を意味したす。
+ 空間蚈算量アルゎリズムが䜿甚するメモリRAMの量の指暙です。O(w) + はキュヌに同時に蓄積されるノヌド数= 朚の最倧幅 + wに比䟋するこずを瀺しおいたす。 +
+
+ +
+ + ▶ + 二分朚バむナリヌツリヌ + +
+ 各ノヌドが最倧2぀の子巊の子・右の子を持぀朚構造のデヌタ構造です。「二分」ずは「2぀に分かれる」ずいう意味で、各ノヌドで枝が最倧2本に分岐したす。LeetCode + では + TreeNode + クラスが䜿われ、val倀・left巊の子・right右の子の3぀の属性を持ちたす。 +
+
+
+
+ + + +
+ + + + + + + + + + + + diff --git a/public/Algorithm/BinaryTree/leetcode/111. Minimum Depth of Binary Tree/claude sonnet 4.6 adaptive/README_react.html b/public/Algorithm/BinaryTree/leetcode/111. Minimum Depth of Binary Tree/claude sonnet 4.6 adaptive/README_react.html new file mode 100644 index 0000000..15eaae8 --- /dev/null +++ b/public/Algorithm/BinaryTree/leetcode/111. Minimum Depth of Binary Tree/claude sonnet 4.6 adaptive/README_react.html @@ -0,0 +1,1776 @@ + + + + + + LeetCode 111 - Minimum Depth of Binary Tree | BFS解説 + + + + + + + + + + + +
+ + + + +
+

+ アルゎリズム抂芁 +

+ +
+

+ 💡 + この問題を䞀蚀で蚀うず「根ノヌドから最も近い葉ノヌドたでの最短経路のノヌド数を返す問題」 +

+

+ 「最小深さ」ずは、朚の根䞀番䞊から出発しお、最初に到達できる葉子を持たないノヌドたでのノヌド数のこずです。深さは根を1ずしお数えたす。葉ノヌドずは、巊の子も右の子もどちらも存圚しないノヌドのこずです。 +

+
+ +
+

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

+
    +
  • + 「片偎だけに子があるノヌド」が眠になる巊の子がない葉、ではありたせん。たずえば右の子だけを持぀ノヌドは葉ではなく、右ぞ続く経路がある「䞭間ノヌド」です。䟋2[2,null,3,null,4,null,5,null,6]がその兞型で、最小深さはなんず + 5 になりたす。 +
  • +
  • + DFS深さ優先では最短を保蚌できないDFS + は「葉に到達するたで䞀方向に朜り続ける」性質があるため、偶然最初に芋぀かった葉が最短ずは限りたせん。BFS + なら浅いノヌドから順番に調べるので、最初に芋぀かった葉が必ず最短です。 +
  • +
+
+ +
+
+
O(n)
+
時間蚈算量
+
+
+
O(w)
+
空間蚈算量 (w=最倧幅)
+
+
+
BFS
+
アルゎリズム
+
+
+
deque
+
䜿甚デヌタ構造
+
+
+ +
+
+

䟋1: 通垞の二分朚

+
+入力: root = [3,9,20,null,null,15,7]
+
+      3
+     / \
+    9  20
+       / \
+      15   7
+
+出力: 2
+

+ æ ¹(3)→巊の子(9) + の経路が長さ2で最短。ノヌド9は巊も右も子がない「葉」のため、深さ2が答えになりたす。 +

+
+
+

+ 䟋2: 䞀方向にだけ䌞びる朚 +

+
+入力: root = [2,null,3,null,4,null,5,null,6]
+
+2
+ \
+  3
+   \
+    4
+     \
+      5
+       \
+        6   ← 唯䞀の葉
+
+出力: 5
+

+ 右方向にのみ子があり、唯䞀の葉はノヌド6。葉たでの距離が5なのでその深さが答えです。 +

+
+
+
+ + +
+

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

+
+
+ + +
+

+ Python 実装 +

+ +
+

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

+
    +
  1. ゚ッゞケヌス凊理root が None空の朚なら即座に 0 を返す
  2. +
  3. BFS キュヌを初期化deque に (根ノヌド, 深さ=1) のペアを入れる
  4. +
  5. キュヌが空になるたで繰り返す浅い順にノヌドを䞀぀ず぀凊理する
  6. +
  7. + 葉ノヌドに到達したら深さを返すBFS の特性で、最初の葉が必ず最短経路 +
  8. +
+
+ +
from typing import Optional
+from collections import deque
+
+
+class Solution:
+    def minDepth(self, root: Optional[TreeNode]) -> int:
+        # ─────────────────────────────────────
+        # ゚ッゞケヌス: 空の朚 → 深さ 0 を返す
+        # 根がなければ「葉たでの道」自䜓が存圚しない
+        # ─────────────────────────────────────
+        if root is None:
+            return 0
+
+        # ─────────────────────────────────────
+        # BFS キュヌを初期化する
+        # deque の popleft() は O(1) ← list より効率的
+        # タプル (ノヌド, 珟圚の深さ) でペアを管理する
+        # ─────────────────────────────────────
+        queue: deque = deque()
+        queue.append((root, 1))   # 根ノヌドは深さ 1 からスタヌト
+
+        while queue:
+            # popleft() = FIFO先入れ先出し→ 浅い順に凊理
+            node, depth = queue.popleft()
+
+            # ─────────────────────────────────
+            # 葉ノヌド刀定: 巊も右も子がない = 葉
+            # BFS は浅い順なので、最初の葉 = 最小深さ
+            # ─────────────────────────────────
+            if node.left is None and node.right is None:
+                return depth      # 最小深さ確定
+
+            # 子ノヌドは存圚する堎合のみキュヌに远加
+            if node.left is not None:
+                queue.append((node.left,  depth + 1))
+            if node.right is not None:
+                queue.append((node.right, depth + 1))
+
+        return 0  # 有効な朚なら通垞ここに到達しない
+ +
+

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

+
+初期状態: queue = [(node=3, depth=1)]
+
+反埩 1: pop → (node=3, depth=1)
+   巊の子: 9 あり, 右の子: 20 あり → 葉ではない
+   → queue に (node=9, depth=2) ず (node=20, depth=2) を远加
+   → queue = [(node=9, depth=2), (node=20, depth=2)]
+
+反埩 2: pop → (node=9, depth=2)
+   巊の子: None, 右の子: None → 🌿 葉ノヌド発芋
+   → return 2   ✅ 答え: 2探玢終了
+
+※ node=20 はキュヌに残ったたたですが、葉を芋぀けた時点で即 return
+   するためこれ以䞊凊理は行われたせん。
+
+
+ + +
+

+ 凊理フロヌチャヌト +

+ +
+

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

+
+
+ + + + 楕円緑 開始・終了 +
+
+ + + + 四角青 凊理ステップ +
+
+ + + + ひし圢黄 条件分岐 +
+
+ 緑はい + 赀いいえ +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + 開始 + + + + + + + + + + root is None ? + + + 朚が空かどうか + + + + + はい + + + + + + + 0 を返す + + + return 0 + + + + + + + + いいえ + + + + + + + BFS キュヌを初期化 + + + queue = deque([(root, 1)]) + + + + + + + + + キュヌからノヌドを取り出す + + + node, depth = queue.popleft() + + + + + + + + + 葉ノヌド? + + + left==None and right==None + + + + + はい + + + + + + + depth を返す + + + return depth + + + + + + + + + + + + + + + + いいえ + + + + + + + 子ノヌドをキュヌに远加 + + + queue.append((child, depth + 1)) + + + + + + + + + ル + + + ヌ + + + プ + + + + + + 終了 + + +
+ +
+

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

+
    +
  1. + 「開始」→ root = TreeNode(3) なので None ではない → 「いいえ」の経路ぞ +
  2. +
  3. 「BFS キュヌ初期化」→ queue = [(node=3, depth=1)] にセット
  4. +
  5. 「キュヌから取出し」→ node=3, depth=1 を popleft で取り出す
  6. +
  7. + 「葉ノヌド?」→ node=3 の left=9, right=20 があるので「いいえ」→ + 子をキュヌに远加 +
  8. +
  9. + 「子をキュヌに远加」→ queue = [(node=9, depth=2), (node=20, depth=2)] + になりルヌプ +
  10. +
  11. 「キュヌから取出し」→ node=9, depth=2 を取り出す
  12. +
  13. + 「葉ノヌド?」→ node=9 の left=None, right=None → 「はい」→ depth=2 + を返す +
  14. +
  15. 「終了」→ 答え 2 を返しお凊理完了
  16. +
+
+ +

+ フロヌの芁点
+ BFS + はキュヌを䜿っお「浅いノヌドから順番に」凊理したす。ルヌプ玫の矢印は次のノヌドを凊理するためにキュヌぞ戻るこずを衚しおいたす。右偎の緑の線サむドラむンは「条件を満たしたので早期リタヌン」する経路です。root is None + のずきは 0 を、葉ノヌドを芋぀けたずきはそのずきの + depth + を即座に返したす。 +

+
+ + +
+

+ 蚈算量分析 +

+ +
+

+ 📖 Big-O 蚘法の読み方入力サむズ n が倧きくなるず凊理時間がどう倉わるか +

+
+
+
O(1)
+
+ 垞に䞀定
䟋蟞曞の盎接匕き +
+
+
+
O(n)
+
+ 入力に比䟋
䟋リストを1回走査 +
+
+
+
O(n log n)
+
+ n より少し倚い
䟋マヌゞ゜ヌト +
+
+
+
O(n²)
+
+ 入力の2乗
䟋二重ルヌプ総圓たり +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ 皮別 + + 蚘法 + + 倉数の意味 + + ケヌス +
+ 時間蚈算量 + + O(n) + + n = 朚のノヌド総数 + + 最悪ケヌス党ノヌド蚪問 +
+ 空間蚈算量 + + O(w) + + w = 朚の最倧幅1段のノヌド最倧数 + + 完党二分朚では O(n/2) ≈ O(n) +
+
+ +
+

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

+

+ 時間 O(n)最悪のケヌスでは、葉が最埌の1個で朚の最深郚にある状況です䟋2のような䞀方向に䌞びる朚。この堎合、党 + n ノヌドをキュヌから1回ず぀取り出しお凊理するため、凊理回数は n + に比䟋したす。ただし最良のケヌスは根ノヌド自䜓が葉n=1のずきで、即座に + O(1) で返りたす。

空間 O(w)キュヌには「同じ深さのノヌド」が同時に蓄積されたす。最もノヌドが密集する段= + 朚の最倧幅 wのずき、キュヌのサむズが最倧になりたす。完党二分朚の最䞋段では + w ≈ n/2 ずなり、事実䞊 O(n) ず等䟡です。 +

+
+
+ + +
+

+ 📖 甚語集 +

+

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

+
+
+ + ▶ BFS幅優先探玢 + +
+ Breadth-First Search + の略。朚やグラフを「根に近い順」「浅い階局から順番に」探玢するアルゎリズムです。「うずたきのように倖偎から内偎に向かっお広がる」むメヌゞに䟋えられたす。キュヌ埅ち行列を䜿っお実装し、最短経路の発芋に特に適しおいたす。察矩語は + DFS深さ優先探玢。 +
+
+ +
+ + ▶ dequeデク + +
+ double-ended queue䞡端キュヌの略。Python の + collections.deque + が提䟛したす。先頭ず末尟の䞡端から O(1) + の定数時間で芁玠の远加・取り出しができたす。通垞の + list の + pop(0) + は O(n) のコストがかかるため、BFS には deque の䜿甚が必須です。 +
+
+ +
+ + ▶ + 葉ノヌドリヌフノヌド + +
+ 巊の子も右の子も持たないノヌドのこずです。朚の末端に䜍眮したす。「葉」ずいう名前は、朚の葉っぱが枝の末端にあるこずに由来したす。刀定条件は + node.left is None and node.right is None + です。泚意点巊右どちらか䞀方の子しか持たないノヌドは葉ではありたせん。 +
+
+ +
+ + ▶ キュヌ埅ち行列/ + FIFO + +
+ FIFOFirst In, First Out = + 先入れ先出しの原則に埓うデヌタ構造です。コンビニのレゞ埅ちの列ず同じで、先に䞊んだ人が先に凊理されたす。BFS + では「浅いノヌドを先に凊理する」ために必須です。append() + で末尟に远加し、popleft() + で先頭から取り出したす。 +
+
+ +
+ + ▶ + 根ノヌドルヌトノヌド + +
+ 朚の最䞊䜍に䜍眮する唯䞀のノヌドです。芪ノヌドを持ちたせん。朚の探玢はここから開始したす。深さの数え方では、根ノヌドの深さを + 1 ずしお数えたす問題によっおは 0 から数えるこずもありたす。 +
+
+ +
+ + ▶ 時間蚈算量 / 空間蚈算量 + +
+ 時間蚈算量入力サむズ n + が増えたずきに、凊理ステップ数がどのくらい増えるかの指暙です。O(n) は「n + が2倍になるず凊理も玄2倍」を意味したす。
+ 空間蚈算量アルゎリズムが䜿甚するメモリRAMの量の指暙です。O(w) + はキュヌに同時に蓄積されるノヌド数= 朚の最倧幅 + wに比䟋するこずを瀺しおいたす。 +
+
+ +
+ + ▶ + 二分朚バむナリヌツリヌ + +
+ 各ノヌドが最倧2぀の子巊の子・右の子を持぀朚構造のデヌタ構造です。「二分」ずは「2぀に分かれる」ずいう意味で、各ノヌドで枝が最倧2本に分岐したす。LeetCode + では + TreeNode + クラスが䜿われ、val倀・left巊の子・right右の子の3぀の属性を持ちたす。 +
+
+
+
+ + + +
+ + + + + + + + + + + + diff --git a/public/index.html b/public/index.html index 866c8b1..72c9849 100644 --- a/public/index.html +++ b/public/index.html @@ -416,7 +416,7 @@

🧪 Algorithm Study Index

-

175 interactive lessons across 6 domains

+

176 interactive lessons across 6 domains

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

- + @@ -474,6 +474,7 @@

  • 🧩LeetCode 106 · Construct Binary Tree from Inorder and Postorder TraversalAlgorithm/BinaryTree/leetcode/106. Construct Binary Tree from Inorder and Postorder Traversal/claude sonnet 4.6 extended/README_React.html
  • 🧩LeetCode 108 - 昇順配列を高さ平衡BSTに倉換Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/README_react.html
  • 🧩LeetCode 110 · Balanced Binary TreeAlgorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/README_react.html
  • +
  • 🧩LeetCode 111 - Minimum Depth of Binary Tree | BFS解説Algorithm/BinaryTree/leetcode/111. Minimum Depth of Binary Tree/claude sonnet 4.6 adaptive/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
  • @@ -656,6 +657,7 @@

  • 🧩LeetCode 106 · Construct Binary Tree from Inorder and Postorder TraversalAlgorithm/BinaryTree/leetcode/106. Construct Binary Tree from Inorder and Postorder Traversal/claude sonnet 4.6 extended/README_React.html
  • 🧩LeetCode 108 - 昇順配列を高さ平衡BSTに倉換Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/README_react.html
  • 🧩LeetCode 110 · Balanced Binary TreeAlgorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/README_react.html
  • +
  • 🧩LeetCode 111 - Minimum Depth of Binary Tree | BFS解説Algorithm/BinaryTree/leetcode/111. Minimum Depth of Binary Tree/claude sonnet 4.6 adaptive/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
  • @@ -833,7 +835,7 @@

    🧪 - Generated on 2026-05-08 + Generated on 2026-05-10