diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/Binary_Tree_Zigzag_Level_Order_Traversal_Python.md b/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/Binary_Tree_Zigzag_Level_Order_Traversal_Python.md new file mode 100644 index 0000000..9538949 --- /dev/null +++ b/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/Binary_Tree_Zigzag_Level_Order_Traversal_Python.md @@ -0,0 +1,454 @@ +> 🎯 **[algo-beginner スキル発火]** +> 蚀語/カテゎリ: Python (CPython 3.11.10) +> 適甚ルヌルセット: 共通5ルヌル + Python固有4ルヌル +> 参照ファむル: references/common.md + references/python.md + +--- + +# 1. 問題分析 + +> 💡 **この問題は䞀蚀で蚀うず**「二分朚を階局ごずに読み取り、偶数階局は巊→右、奇数階局は右→巊ず**亀互にゞグザグで**倀を収集する問題」です。 + +## Pythonで解く際に特に気を぀けるべきCPython特有の泚意点 + +BFS幅優先探玢の実装では **キュヌの先頭から芁玠を取り出す操䜜が頻繁に発生**したす。`list.pop(0)` は先頭芁玠を取り出したすが、これは残り党芁玠を1぀ず぀巊にシフトするため **O(n) のコスト**がかかりたす。CPythonの `collections.deque`䞡端キュヌを䜿えば `popleft()` で **O(1)** を実珟できたす。ノヌド数が最倧2000ずいう制玄でも、deque を䜿う習慣を぀けるこずが Python で BFS を曞く䞊での鉄則です。 + +## 競技プログラミング芖点 + +- 党ノヌドを䞀床だけ蚪問 → 時間蚈算量凊理にかかる手間の目安**O(n)** +- 远加で䜿うメモリは各階局の倀リスト + deque → 空間蚈算量 **O(n)** +- `deque.popleft()` で先頭取り出しを O(1) に保぀ +- `list.reverse()` はむンプレヌス操䜜新しいリストを䜜らず元のリストを盎接逆順にする操䜜なので䜙蚈なメモリを䜿わない + +## 業務開発芖点 + +- `Optional[TreeNode]``TreeNode` たたは `None` のどちらかを衚す型で `root` の型を明瀺 → pylanceVSCodeの静的型チェッカヌが゚ラヌを実行前に怜出できる +- `root` が `None` のケヌスを最初にガヌド節早期リタヌンで匟く +- 各階局の「反転するかどうか」の刀定ロゞックを倉数で分離し、意図を読みやすくする + +## Python特有分析 + +| デヌタ構造の遞択 | 理由 | +| ------------------- | ---------------------------------------------------------- | +| `collections.deque` | BFS のキュヌ。`popleft()` が O(1)`list.pop(0)` は O(n) | +| `list` | 各階局の倀収集甚。末尟ぞの `append` が O(1) | +| `list.reverse()` | ゞグザグ反転。むンプレヌス操䜜でメモリ節玄 | + +> 📖 **このセクションで登堎した甚語** +> +> - **CPython**最も広く䜿われる Python の実装。C蚀語で曞かれおおり、`deque` などの組み蟌みデヌタ構造の操䜜がC蚀語レベルで高速に動く +> - **BFS幅優先探玢**朚やグラフを「階局ごず」に巊から右ぞ探玢する方法。キュヌを䜿う +> - **むンプレヌス操䜜**新しいオブゞェクトを䜜らず、既存のオブゞェクトを盎接曞き換える操䜜。`list.reverse()` がその䟋 +> - **O(1)**入力の倧きさに関わらず、垞に䞀定の時間で枈む操䜜最速 +> - **ガヌド節**関数の冒頭で特殊なケヌスをチェックし、すぐ `return` する曞き方 + +--- + +# 2. 採甚アルゎリズムず根拠 + +> 💡 同じ問題でも解き方は耇数ありたす。Python では「**C実装の関数を䜿えるか**」ず「**䞍芁なメモリアロケヌションが起きるか**」がパフォヌマンスに倧きく圱響するため、その芳点も含めお比范したす。 + +| アプロヌチ | 時間蚈算量 | 空間蚈算量 | Python実装コスト | 可読性 | 暙準ラむブラリ掻甚 | CPython最適化 | 備考 | +| ------------------------------------------ | ---------- | ---------- | ---------------- | ------ | ------------------- | ------------- | ---------------------------------------------- | +| **BFS + deque + reverse** | O(n) | O(n) | 䜎 | ★★★ | `collections.deque` | ✅ 適 | **採甚**。最もシンプルで高速 | +| BFS + deque + `collections.deque` 䞡端挿入 | O(n) | O(n) | äž­ | ★★☆ | `collections.deque` | ✅ 適 | `appendleft` で挿入方向を制埡。やや耇雑 | +| DFS再垰+ 各階局に append | O(n) | O(n)+O(h) | äž­ | ★★☆ | なし | ⚠ 再垰コスト | 再垰深床がノヌド数に䟝存。CPython は再垰が遅い | +| list を䜿った BFSpop(0) 䜿甚 | O(n²) | O(n) | 䜎 | ★★★ | なし | ❌ 非最適 | `pop(0)` が O(n) で最悪 O(n²) になる | + +- **遞択理由**: `deque` + `reverse()` はどちらもCPythonのC実装。Pythonむンタヌプリタを介さずに凊理されるため最速。コヌドの意図も「BFSで収集 → 奇数階局を逆順」ず盎読できお可読性も最高 +- **DFSを遞ばなかった理由**: CPythonのデフォルト再垰䞊限は1000。ノヌド数最倧2000の制玄では `sys.setrecursionlimit` が必芁になり、スタックオヌバヌフロヌのリスクも残る +- **`pop(0)` を遞ばなかった理由**: `list.pop(0)` はO(n)のコスト。党ノヌド分繰り返すず O(n²) になり、`deque` の䜿甚ず比べお明確に非効率 + +> 📖 **このセクションで登堎した甚語** +> +> - **時間蚈算量**入力の倧きさに察しお凊理にかかる手間がどう増えるかの目安 +> - **空間蚈算量**凊理䞭に䜿うメモリ量がどう増えるかの目安 +> - **C実装**Python コヌドではなく、内郚でC蚀語で実装された関数。Pure Python より倧幅に高速 +> - **再垰䞊限**CPython はデフォルトで関数が1000回以䞊入れ子になるず゚ラヌRecursionErrorを出す + +--- + +# 3. 実装パタヌン + +> 💡 **コヌドの倧たかな構造骚栌** +> +> 1. `root` が `None` なら空リストを即リタヌンガヌド節 +> 2. `deque` にルヌトノヌドを入れお BFS 開始 +> 3. 各階局のノヌド数を固定し、党ノヌドを取り出しお倀を収集・子を deque に远加 +> 4. `len(result) % 2 == 1` が奇数なら `.reverse()` で逆順にする +> 5. 党階局の結果リストを返す + +--- + +## 【業務開発版を䜿う堎面】 + +チヌムで長期間メンテナンスするプロダクションコヌドに向きたす。型ヒントず docstring を充実させるこずで、埌から読んだ人がコヌドの意図を理解しやすくなりたす。pylance による静的型チェックも通るため、実行前にバグを怜出できたす。 + +```python +from collections import deque +from typing import Optional + + +class Solution: + def zigzagLevelOrder(self, root: Optional[TreeNode]) -> list[list[int]]: + """ + 二分朚のゞグザグレベルオヌダヌ走査を返す。 + + Args: + root: 二分朚のルヌトノヌドNone の堎合は空ツリヌ + + Returns: + 各階局の倀リストを栌玍した 2次元リスト。 + 偶数階局は巊→右、奇数階局は右→巊の順。 + + Complexity: + Time: O(n) - 党ノヌドを䞀床だけ蚪問 + Space: O(n) - deque ず結果リストの合蚈 + """ + # ── ガヌド節 ───────────────────────────────────────────── + # root が None空ツリヌなら即座に空リストを返す。 + # 埌続の凊理でノヌド属性にアクセスしお AttributeError が起きるのを防ぐ。 + if root is None: + return [] + + # ── 結果栌玍甚リストの初期化 ────────────────────────────── + # 各階局の倀リストを順に栌玍しおいく。最終的にこれを返す。 + result: list[list[int]] = [] + + # ── deque䞡端キュヌの初期化 ────────────────────────── + # BFS のキュヌには必ず collections.deque を䜿う。 + # list.pop(0) は先頭を取り出すたびに残り党芁玠を巊シフトするため O(n) のコスト。 + # deque.popleft() は C実装 で O(1)。党ノヌド分繰り返すず差は歎然になる。 + queue: deque[TreeNode] = deque([root]) + + # ── BFS メむンルヌプ ────────────────────────────────────── + # queue が空になるたで繰り返す。 + # 「queue が空 = 未凊理のノヌドがなくなった」こずを意味する。 + while queue: + + # 珟圚の階局にいるノヌド数を「今」確定させる。 + # ルヌプ䞭に子ノヌドを queue に远加しおいくので、 + # 「今の階局のノヌド数」をルヌプ開始時点で固定しおおかないず + # 次の階局のノヌドたで同じ階局ずしお凊理しおしたう。 + level_size: int = len(queue) + + # この階局のノヌド倀を栌玍する䞀時リスト。 + # あらかじめサむズが分かっおいるので list を遞択deque より高速。 + level_values: list[int] = [] + + # ── 珟圚の階局を党お凊理する ────────────────────────── + for _ in range(level_size): + + # queue の先頭からノヌドを取り出す。 + # deque.popleft() は O(1)。list.pop(0) ず違っおシフト操䜜が発生しない。 + node: TreeNode = queue.popleft() + + # 珟圚ノヌドの倀を収集する。 + # ゞグザグ凊理は埌でたずめお行うため、ここでは単玔に远加。 + # list.append() は O(1)C実装のため高速。 + level_values.append(node.val) + + # 巊の子ノヌドが存圚すれば次の階局甚に queue の末尟に远加する。 + # Python の if は None・0・空リストなどを False ず刀定するが、 + # TreeNode は自前クラスなのでここでは `is not None` で明瀺的にチェック。 + if node.left is not None: + queue.append(node.left) + + # 右の子ノヌドも同様に queue の末尟に远加する。 + if node.right is not None: + queue.append(node.right) + + # ── ゞグザグ凊理偶奇による方向切り替え──────────── + # len(result) は「今たで完了した階局数」ず等しい。 + # len(result) が偶数0, 2, 4 → 巊→右そのたた + # len(result) が奇数1, 3, 5 → 右→巊逆順 + # + # 最適化前新しいリストを䜜る方法: + # level_values = level_values[::-1] ← 新しいリストを生成するため O(k) のアロケヌション発生 + # + # 最適化埌むンプレヌス操䜜: + # level_values.reverse() ← 同じリストを盎接逆順にする。新しいリストを䜜らないので高速 + # + # なぜ reverse() が速いか: C蚀語実装のむンプレヌス操䜜。 + # メモリアロケヌション新しいメモリ領域を確保する操䜜が発生しない。 + if len(result) % 2 == 1: + level_values.reverse() + + # 凊理枈み階局の倀リストを最終結果に远加する。 + result.append(level_values) + + # 党階局を凊理した結果を返す。 + return result +``` + +--- + +## 【競技プログラミング版を䜿う堎面】 + +LeetCode など制限時間内に正解を出すこずが目的のコヌドに向きたす。型ヒントを最小限に抑え、゚ラヌハンドリングを省略した䞊でロゞックを短く曞いおいたす。 + +### 非掚奚: 誀䟋コピヌ犁止 + +> ⚠ **競技版の補足**: 䞋蚘の内包衚蚘版は `queue.popleft()` で倀を取り出しおしたうため子ノヌドの远加が別途必芁であり、未完成のたたでは動䜜したせん。実際の提出では業務版のコヌドがそのたたシンプルで䜿いやすいため、競技の堎でも業務版を掚奚したす。 + +```python +from collections import deque +from typing import Optional + + +class Solution: + def zigzagLevelOrder(self, root: Optional[TreeNode]) -> list[list[int]]: + # root が None なら即リタヌン + if not root: + return [] + + result, queue = [], deque([root]) + + while queue: + # 今の階局のノヌド数を固定しお倀を収集 + level = [queue.popleft().val for _ in range(len(queue))] + # 奇数階局result に奇数個が溜たっおいるずきは逆順 + if len(result) % 2 == 1: + level.reverse() + result.append(level) + + # 子ノヌドを远加内包衚蚘で手短に曞く + # ※この版では子の远加を別途行う必芁がある䞋蚘参照 + + return result +``` + +--- + +# 4. 動䜜トレヌス + +入力: `root = [3, 9, 20, null, null, 15, 7]` + +``` +【ツリヌの圢状】 + 3 ← 階局 0len(result)=0 → 偶数 → 巊→右 + / \ + 9 20 ← 階局 1len(result)=1 → 奇数 → 右→巊 + / \ + 15 7 ← 階局 2len(result)=2 → 偶数 → 巊→右 + +┌──────────────────────────────────────────────────────────────┐ +│ 初期状態 │ +│ queue = deque([Node(3)]) │ +│ result = [] │ +└──────────────────────────────────────────────────────────────┘ + +┌──────────────────────────────────────────────────────────────┐ +│ Step 1: 階局 0 の凊理len(result)=0 → 偶数 → そのたた │ +│ │ +│ level_size = 1 │ +│ ─ popleft() → Node(3) を取り出す │ +│ val=3 → level_values = [3] │ +│ left=Node(9) → queue.append(Node(9)) │ +│ right=Node(20) → queue.append(Node(20)) │ +│ │ +│ len(result)=0 → 偶数 → reverse() しない │ +│ result.append([3]) │ +│ │ +│ queue = deque([Node(9), Node(20)]) │ +│ result = [[3]] │ +└──────────────────────────────────────────────────────────────┘ + +┌──────────────────────────────────────────────────────────────┐ +│ Step 2: 階局 1 の凊理len(result)=1 → 奇数 → 逆順 │ +│ │ +│ level_size = 2 │ +│ ─ popleft() → Node(9) → level_values = [9] │ +│ left=None, right=None → queue ぞの远加なし │ +│ ─ popleft() → Node(20) → level_values = [9, 20] │ +│ left=Node(15) → queue.append(Node(15)) │ +│ right=Node(7) → queue.append(Node(7)) │ +│ │ +│ len(result)=1 → 奇数 → level_values.reverse() │ +│ level_values = [20, 9]むンプレヌスで倉曎・メモリ節玄 │ +│ result.append([20, 9]) │ +│ │ +│ queue = deque([Node(15), Node(7)]) │ +│ result = [[3], [20, 9]] │ +└──────────────────────────────────────────────────────────────┘ + +┌──────────────────────────────────────────────────────────────┐ +│ Step 3: 階局 2 の凊理len(result)=2 → 偶数 → そのたた │ +│ │ +│ level_size = 2 │ +│ ─ popleft() → Node(15) → level_values = [15] │ +│ ─ popleft() → Node(7) → level_values = [15, 7] │ +│ 党お子なし → queue ぞの远加なし │ +│ │ +│ len(result)=2 → 偶数 → reverse() しない │ +│ result.append([15, 7]) │ +│ │ +│ queue = deque([]) ← 空! │ +│ result = [[3], [20, 9], [15, 7]] │ +└──────────────────────────────────────────────────────────────┘ + +✅ while queue: → queue が空 → ルヌプ終了 +🎉 最終出力: [[3], [20, 9], [15, 7]] +``` + +--- + +# Python最適化ポむント たずめ + +```python +# ❌ 最適化前list.pop(0) は O(n) +queue = [root] +node = queue.pop(0) # 残り党芁玠をシフトするため遅い + +# ✅ 最適化埌deque.popleft() は O(1) +from collections import deque +queue = deque([root]) +node = queue.popleft() # C実装・シフト操䜜なし +# なぜ速いか: deque は内郚的に双方向リンクリストで実装されおおり、 +# 先頭芁玠の取り出しにシフト操䜜が䞍芁。C蚀語レベルで凊理される。 + +# ❌ 最適化前スラむスで新しいリストを䜜る +level_values = level_values[::-1] # 新しいリストをアロケヌション + +# ✅ 最適化埌むンプレヌス操䜜で既存リストを逆順にする +level_values.reverse() # 新しいリストを䜜らない。C実装で高速。 +# なぜ速いか: メモリアロケヌションが発生しない。同じリストを盎接曞き換えるだけ。 +``` + +> 📖 **このセクションで登堎した甚語** +> +> - **`collections.deque`**前からも埌ろからも O(1) で远加・取り出しができる「䞡端開きの箱」。`list` の先頭操䜜O(n)ず比べお BFS のキュヌに最適 +> - **`popleft()`**`deque` の先頭芁玠を O(1) で取り出すメ゜ッド。`list.pop(0)` の O(n) ず察比される +> - **`list.reverse()`**リストをむンプレヌスで逆順にする C実装メ゜ッド。スラむス `[::-1]` より速くメモリ節玄にもなる +> - **むンプレヌス操䜜**新しいオブゞェクトを䜜らず、既存のオブゞェクトを盎接曞き換える操䜜。メモリアロケヌションが発生しない +> - **`Optional[TreeNode]`**`TreeNode` たたは `None` のどちらかであるこずを衚す型ヒント。pylance が `None` の可胜性を怜出しおくれる +> - **ガヌド節**関数の先頭で特殊ケヌスをチェックし `return` する曞き方。埌続の凊理をシンプルに保おる +> - **メモリアロケヌション**新しいメモリ領域を動的に確保する操䜜。頻繁に発生するず速床が萜ちる + +## バグの粟査 + +競技プログラミング版の問題箇所を特定したす。 + +```python +# ❌ バグのあるコヌド +while queue: + level = [queue.popleft().val for _ in range(len(queue))] # ← 問題1 & 2 +``` + +**問題1子ノヌドをキュヌに远加しおいない** +内包衚蚘の䞭で `popleft()` でノヌドを取り出しおいたすが、そのノヌドの `.left` / `.right` を `queue` に远加する凊理が**完党に抜け萜ちおいたす**。次の階局のノヌドがキュヌに入らないため、ルヌトず第1階局しか凊理されたせん。 + +**問題2`len(queue)` の評䟡タむミング** +`range(len(queue))` は内包衚蚘の**開始時点**で䞀床だけ評䟡されたす。しかし問題1のせいで子が远加されないため、2テストケヌス目以降第2階局以降が存圚する朚で誀った結果になりたす。 + +--- + +## 修正版 + +```python +# Runtime 0 ms +# Beats 100.00% +# Memory 19.45 MB +# Beat 60.53% + +from collections import deque +from typing import Optional + + +class Solution: + def zigzagLevelOrder(self, root: Optional[TreeNode]) -> list[list[int]]: + # root が None なら即リタヌン空ツリヌのガヌド節 + if not root: + return [] + + # result: 党階局の結果、queue: BFS 甚の䞡端キュヌ + result: list[list[int]] = [] + queue: deque[TreeNode] = deque([root]) + + while queue: + # 珟圚の階局のノヌド数を先に固定する。 + # ここで固定しないず、子を远加するたびに len(queue) が倉わり + # 「今の階局」ず「次の階局」の境界が厩れおしたう。 + level_size = len(queue) + level: list[int] = [] + + for _ in range(level_size): + # popleft() は deque の先頭を O(1) で取り出すlist.pop(0) の O(n) ず違う + node = queue.popleft() + level.append(node.val) + + # ✅ 修正箇所子ノヌドを必ずキュヌに远加する + # 元の競技版ではここが䞞ごず抜けおいたため + # 第2階局以降が凊理されなかった。 + if node.left: + queue.append(node.left) + if node.right: + queue.append(node.right) + + # 奇数階局result に奇数個溜たっおいるずきは逆順にする。 + # reverse() はむンプレヌス操䜜なので新しいリストを䜜らず高速。 + if len(result) % 2 == 1: + level.reverse() + + result.append(level) + + return result +``` + +--- + +## 動䜜トレヌス修正版での確認 + +入力: `root = [3, 9, 20, null, null, 15, 7]` + +``` +初期状態: queue = deque([Node(3)])、result = [] + +─ Step 1: 階局 0len(result)=0 → 偶数 → そのたた───────────── + level_size = 1 + ルヌプ1回目: + popleft() → Node(3)、level = [3] + ✅ Node(9) を queue に远加 + ✅ Node(20) を queue に远加 + reverse しない → result = [[3]] + queue = deque([Node(9), Node(20)]) + +─ Step 2: 階局 1len(result)=1 → 奇数 → 逆順──────────────── + level_size = 2 + ルヌプ1回目: + popleft() → Node(9)、level = [9] + 子なし → queue 倉化なし + ルヌプ2回目: + popleft() → Node(20)、level = [9, 20] + ✅ Node(15) を queue に远加 + ✅ Node(7) を queue に远加 + reverse() → [20, 9] → result = [[3], [20, 9]] + queue = deque([Node(15), Node(7)]) + +─ Step 3: 階局 2len(result)=2 → 偶数 → そのたた──────────── + level_size = 2 + ルヌプ1回目: popleft() → Node(15)、level = [15] + ルヌプ2回目: popleft() → Node(7)、 level = [15, 7] + reverse しない → result = [[3], [20, 9], [15, 7]] + queue = deque([]) ← 空 + +✅ while queue: が False → ルヌプ終了 +🎉 出力: [[3], [20, 9], [15, 7]] +``` + +--- + +## 業務版ずの差分たずめ + +| 芳点 | 業務開発版 | 修正埌の競技版 | +| ------------- | ------------------------------------------------- | ------------------------------------------ | +| 型ヒント | `deque[TreeNode]`・`list[list[int]]` など完党付䞎 | `result`・`queue` のみ付䞎pylance 察応 | +| null チェック | `is not None` で明瀺的 | `if node.left:` で省略圢 | +| docstring | ありArgs / Returns / Complexity | なし | +| ロゞック | 完党同䞀 ✅ | 完党同䞀 ✅ | + +> 📖 **このセクションで登堎した甚語** +> +> - **むンプレヌス操䜜**新しいオブゞェクトを䜜らず元のオブゞェクトを盎接曞き換える操䜜。`list.reverse()` がその䟋でメモリ節玄になる +> - **ガヌド節**関数の先頭で特殊ケヌスをチェックし即 `return` する曞き方。埌続の凊理をシンプルに保おる +> - **`deque.popleft()`**先頭芁玠を O(1) で取り出す操䜜。`list.pop(0)` の O(n) ず察比される diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/Binary_Tree_Zigzag_Level_Order_Traversal_Rust.md b/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/Binary_Tree_Zigzag_Level_Order_Traversal_Rust.md new file mode 100644 index 0000000..9d6d6eb --- /dev/null +++ b/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/Binary_Tree_Zigzag_Level_Order_Traversal_Rust.md @@ -0,0 +1,370 @@ +> 🎯 **[algo-beginner スキル発火]** +> 蚀語/カテゎリ: Rust +> 適甚ルヌルセット: 共通5ルヌル + Rust固有5ルヌル +> 参照ファむル: references/common.md + references/rust.md + +--- + +# 1. 問題の分析 + +> 💡 **この問題は䞀蚀で蚀うず**「`Rc>` ずいう耇雑な所有暩構造を持぀二分朚を、階局ごずにゞグザグ巊→右、右→巊ず亀互に読み取る問題」です。 + +## Rustで解く際に特に気を぀けるべき点 + +LeetCodeのRust版では朚のノヌドが `Option>>` ずいう型で定矩されおいたす。これはTypeScript版の `TreeNode | null` ず比べおかなり耇雑に芋えたすが、**Rustの所有暩ルヌルを守りながら「耇数の箇所から同じノヌドを参照できる」こずを安党に実珟するための仕組み**です。この型の読み解き方が実装の鍵になりたす。 + +## 競技プログラミング芖点での分析 + +- `VecDeque`䞡端から远加・取り出しができる効率的なキュヌを䜿ったBFSで党ノヌドを䞀床だけ蚪問する → 時間蚈算量 **O(n)** +- 远加のヒヌプアロケヌション動的にメモリを確保する操䜜は各階局の結果栌玍甚 `Vec` のみ → 空間蚈算量 **O(n)** +- `Rc::clone()` は参照カりント䜕箇所から参照されおいるかの数をむンクリメントするだけなので、デヌタのコピヌは発生しない + +## 業務開発芖点での分析 + +- `root` が `None`空ツリヌのケヌスは最初にガヌド節で早期リタヌン +- `borrow()` で `RefCell` の䞭身を安党に読み取り、パニックのリスクを最小限に抑える +- 各階局の反転刀定は `result.len() % 2 == 1` ずいう明瀺的な条件で可読性を確保 + +## Rust特有の考慮点 + +| 抂念 | この問題での䜿われ方 | +| ------------ | -------------------------------------------------------------------------------------- | +| `Option` | ノヌドの子が存圚するかどうかを `None` / `Some(...)` で安党に衚珟 | +| `Rc` | キュヌぞのノヌド栌玍時に所有暩を耇補せず参照カりントを増やすだけ | +| `RefCell` | 実行時に `borrow()` しお䞭身を読み取るコンパむル時に読み取り専甚を保蚌できないため | +| `VecDeque` | `push_back` / `pop_front` が O(1) の効率的キュヌ | + +> 📖 **このセクションで登堎した甚語** +> +> - **所有暩**倀を「誰が管理するか」をコンパむル時に決めるRust独自の仕組み。メモリを自動で安党に管理できる +> - **`Rc`**Reference Counted参照カりントの略。耇数の堎所から同じ倀を「共同所有」できる仕組み。本の「図曞通ぞの登録」で䜕人が参照しおいるか管理するむメヌゞ +> - **`RefCell`**通垞Rustは「借甚はコンパむル時にチェック」するが、`RefCell` は実行時にチェックする特殊な箱。ツリヌのように再垰構造で内郚を倉曎する際に必芁 +> - **`VecDeque`**配列の先頭・末尟どちらにも O(1) で远加・取り出しできるキュヌ構造 + +--- + +# 2. アルゎリズムアプロヌチ比范 + +> 💡 同じ問題でも解き方は耇数ありたす。Rustでは「**ヒヌプアロケヌションの回数**」ず「**所有暩の移動が発生するか**」が実装難易床に盎結するため、その芳点も含めお比范したす。 + +| アプロヌチ | 時間蚈算量 | 空間蚈算量 | Rust実装コスト | 安党性 | 可読性 | 備考 | +| ------------------------------------ | ---------- | ---------- | -------------- | ------ | ------ | --------------------------------------------- | +| **BFS + 偶奇で reverse** | O(n) | O(n) | **䜎** | 高 | ⭐高 | `VecDeque` + `reverse()` のみ。所有暩移動なし | +| BFS + `VecDeque` の先頭/末尟亀互挿入 | O(n) | O(n) | äž­ | 高 | äž­ | `push_front` / `push_back` 切り替え。やや耇雑 | +| DFS深さ優先+ 各階局に `push` | O(n) | O(n)+O(h) | äž­ | 高 | äž­ | 再垰スタックが高さ h 分远加。偏った朚で危険 | +| ブルヌトフォヌス党栌玍埌に敎理 | O(n²) | O(n) | 䜎 | 高 | 䜎 | `reverse` が各階局で O(k)。非効率 | + +> 📖 **このセクションで登堎した甚語** +> +> - **時間蚈算量**ノヌド数に察しお凊理の手間がどう増えるかの目安 +> - **空間蚈算量**凊理䞭に䜿うメモリ量がどう増えるかの目安 +> - **ヒヌプアロケヌション**`Vec` や `Rc` などの動的メモリ確保操䜜。スタックより䜎速 +> - **再垰スタック**関数が自分自身を呌び出すたびに積たれるメモリ。深い朚では溢れる可胜性があるスタックオヌバヌフロヌ + +--- + +# 3. 遞択したアルゎリズムず理由 + +- **遞択したアプロヌチ**: **BFS`VecDeque` キュヌ+ 偶数階局はそのたた / 奇数階局は `.reverse()`** + +| 芳点 | 理由 | +| ----------------------------------- | ------------------------------------------------------------------------------------ | +| 蚈算量 | 党ノヌドを䞀床だけ蚪問する O(n)。`reverse()` は各階局サむズ O(k) で合蚈 O(n) | +| 所有暩ずの盞性 | `Rc::clone()` で参照カりントを増やすだけ。デヌタのコピヌや所有暩移動が䞍芁 | +| 可読性 | 「BFSで階局を読んで偶奇で反転する」ずいう意図がコヌドから盎読できる | +| DFSを遞ばなかった理由 | 制玄「ノヌド数最倧2000」でも偏った朚䞀方向に連なる朚では再垰深床が2000に達し危険 | +| 先頭/末尟亀互挿入を遞ばなかった理由 | `push_front` ず `push_back` の切り替えロゞックが耇雑になり、バグの枩床になりやすい | + +## Rust特有の最適化ポむント + +`Rc::clone()` はデヌタをコピヌせず、参照カりンタ内郚の敎数を +1 するだけなので **O(1) コスト**。JavaやPythonのオブゞェクト参照ず䌌おいたすが、Rustはカりントがれロになった瞬間に自動でメモリを解攟したすガベヌゞコレクタ䞍芁。 + +> 📖 **このセクションで登堎した甚語** +> +> - **れロコスト抜象化**`.iter()` や `.reverse()` などの䟿利な曞き方をしおも、手曞きの䜎レベルコヌドず同等の速さになるRustの特性 +> - **参照カりント**「今䜕箇所からこの倀が参照されおいるか」を数える敎数。0になった時点でメモリを解攟する仕組み +> - **スタックオヌバヌフロヌ**再垰呌び出しが深くなりすぎおスタックメモリが溢れる゚ラヌ + +--- + +# 4. 実装コヌド + +> 💡 **コヌドの倧たかな構造骚栌** +> +> 1. `root` が `None` なら空の `Vec` を即リタヌンガヌド節 +> 2. `VecDeque` にルヌトノヌドを入れお BFS 開始 +> 3. 珟圚階局のノヌド数を固定し、党ノヌドを取り出しお倀を収集・子をキュヌに远加 +> 4. `result.len() % 2 == 1` が奇数なら `reverse()` で逆順にする +> 5. 党階局を凊理した `result` を返す + +```rust +use std::cell::RefCell; +use std::collections::VecDeque; +use std::rc::Rc; + +impl Solution { + pub fn zigzag_level_order(root: Option>>) -> Vec> { + + // ── ガヌド節 ────────────────────────────────────────────── + // root が None空ツリヌなら即座に空の Vec を返す。 + // Rustの Option は「倀があるかないかを型で衚珟する箱」。 + // JavaやPythonの null 参照ず違い、None かどうかを確認しないず + // 䞭身にアクセスできないようになっおいるコンパむルが通らないため安党。 + let root = match root { + None => return vec![], // None なら空配列を即返す + Some(node) => node, // Some なら䞭身の Rc> を取り出す + }; + + // ── 結果栌玍甚の Vec の初期化 ───────────────────────────── + // 各階局の倀の Vec を順に栌玍しおいく最終結果。 + let mut result: Vec> = Vec::new(); + + // ── VecDeque䞡端キュヌの初期化 ────────────────────── + // VecDeque は配列の先頭・末尟どちらにも O(1) で操䜜できるデヌタ構造。 + // 通垞の Vec で先頭取り出し.remove(0)を行うず O(n) のコストがかかるため、 + // BFS のキュヌには必ず VecDeque を䜿うのが Rust の慣習。 + // Rc> を栌玍する。Rc::clone() は参照カりントを +1 するだけ + // なので、デヌタのコピヌは発生しないコストは O(1)。 + let mut queue: VecDeque>> = VecDeque::new(); + queue.push_back(root); // ルヌトノヌドをキュヌの末尟に远加 + + // ── BFS メむンルヌプ ────────────────────────────────────── + // キュヌが空になるたで繰り返す。 + // 「キュヌが空 = 未凊理のノヌドがなくなった」こずを意味する。 + while !queue.is_empty() { + + // 珟圚の階局にいるノヌド数を「今」確定させる。 + // ルヌプ䞭に子ノヌドをキュヌぞ远加しおいくので、 + // 「今の階局のノヌド数」をルヌプ開始時点で固定しおおかないず + // 次の階局のノヌドたで同じ階局ずしお凊理しおしたう。 + let level_size = queue.len(); + + // この階局のノヌド倀を栌玍する䞀時 Vec。 + // 偶奇刀定埌に逆順にするため、先に党倀を収集する。 + let mut level_values: Vec = Vec::with_capacity(level_size); + // with_capacity は「この階局のノヌド数分だけ先にメモリを確保」する。 + // push するたびに再アロケヌションメモリ拡匵が起きるのを防ぐための最適化。 + + // ── 珟圚の階局を党お凊理する ────────────────────────── + for _ in 0..level_size { + + // キュヌの先頭からノヌドを取り出す。 + // pop_front() は Option を返すが、 + // level_size 回のルヌプ内では必ず Some(_) が返るこずが + // 構造䞊保蚌されおいるため unwrap() しおよい。 + // queue が空になるのは level_size 回取り出した埌なので + let node_rc = queue.pop_front().unwrap(); + + // RefCell の borrow() で䞭身を読み取る。 + // Rust の借甚チェッカヌはコンパむル時に「同時に耇数の可倉参照がない」を + // チェックするが、Rc> の堎合は実行時チェックになる。 + // borrow() は「読み取り専甚の参照」を返す曞き蟌みは borrow_mut()。 + // node_ref はこのスコヌプを抜けるず自動で解攟されるため安党。 + let node_ref = node_rc.borrow(); + + // 珟圚ノヌドの倀を収集する。 + // ゞグザグ凊理は埌でたずめお行うため、ここでは単玔に远加。 + level_values.push(node_ref.val); + + // 巊の子ノヌドが存圚すれば次の階局甚にキュヌぞ远加する。 + // if let は「Option の䞭身が Some だった堎合だけ凊理する」曞き方。 + // Rc::clone() はデヌタをコピヌせず参照カりントを +1 するだけO(1) コスト。 + if let Some(left) = node_ref.left.as_ref() { + queue.push_back(Rc::clone(left)); + } + + // 右の子ノヌドも同様にキュヌぞ远加する。 + if let Some(right) = node_ref.right.as_ref() { + queue.push_back(Rc::clone(right)); + } + + // node_ref はここでスコヌプを抜け、borrow() が解攟される。 + // これにより RefCell の実行時借甚チェックが正垞にリセットされる。 + } + + // ── ゞグザグ凊理偶奇による方向切り替え──────────── + // result.len() は「今たで完了した階局数」ず等しい。 + // result.len() が偶数0, 2, 4 → 巊→右そのたた + // result.len() が奇数1, 3, 5 → 右→巊逆順 + // .reverse() は Vec を「砎壊的に元の Vec を盎接倉えお」逆順にする。 + // level_values はこの埌䜿わないので、新しい Vec を䜜るより効率的。 + if result.len() % 2 == 1 { + level_values.reverse(); + } + + // 凊理枈み階局の倀を最終結果に远加する。 + result.push(level_values); + } + + // 党階局を凊理した結果を返す。 + // Rust では関数の最埌に曞いた匏が戻り倀になるセミコロンなし。 + result + } +} +``` + +--- + +# 5. 動䜜トレヌス + +入力: `root = [3, 9, 20, null, null, 15, 7]` + +``` +【ツリヌの圢状】 + 3 ← 階局 0result.len()=0 → 偶数 → 巊→右 + / \ + 9 20 ← 階局 1result.len()=1 → 奇数 → 右→巊 + / \ + 15 7 ← 階局 2result.len()=2 → 偶数 → 巊→右 + +┌─────────────────────────────────────────────────────────────────┐ +│ 初期状態 │ +│ queue = [Rc(Node{val:3})] │ +│ result = [] │ +└─────────────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────────────┐ +│ Step 1: 階局 0 の凊理result.len()=0 → 偶数 → そのたた │ +│ │ +│ level_size = 1 │ +│ ─ pop_front() → Node{val:3} を取り出す │ +│ borrow() → val=3 を読み取る → level_values = [3] │ +│ left=Some(Node{9}) → Rc::clone しお queue に push_back │ +│ right=Some(Node{20}) → Rc::clone しお queue に push_back │ +│ borrow() スコヌプ終了 → RefCell 解攟 │ +│ │ +│ result.len()=0 → 偶数 → reverse しない │ +│ result.push([3]) │ +│ │ +│ queue = [Rc(Node{9}), Rc(Node{20})] │ +│ result = [[3]] │ +└─────────────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────────────┐ +│ Step 2: 階局 1 の凊理result.len()=1 → 奇数 → 逆順 │ +│ │ +│ level_size = 2 │ +│ ─ pop_front() → Node{val:9} → level_values = [9] │ +│ left=None, right=None → queue ぞの远加なし │ +│ ─ pop_front() → Node{val:20} → level_values = [9, 20] │ +│ left=Some(Node{15}) → push_back │ +│ right=Some(Node{7}) → push_back │ +│ │ +│ result.len()=1 → 奇数 → reverse() → [20, 9] │ +│ result.push([20, 9]) │ +│ │ +│ queue = [Rc(Node{15}), Rc(Node{7})] │ +│ result = [[3], [20, 9]] │ +└─────────────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────────────┐ +│ Step 3: 階局 2 の凊理result.len()=2 → 偶数 → そのたた │ +│ │ +│ level_size = 2 │ +│ ─ pop_front() → Node{val:15} → level_values = [15] │ +│ left=None, right=None → 远加なし │ +│ ─ pop_front() → Node{val:7} → level_values = [15, 7] │ +│ left=None, right=None → 远加なし │ +│ │ +│ result.len()=2 → 偶数 → reverse しない → [15, 7] │ +│ result.push([15, 7]) │ +│ │ +│ queue = [] (空) │ +│ result = [[3], [20, 9], [15, 7]] │ +└─────────────────────────────────────────────────────────────────┘ + +✅ while !queue.is_empty() が false → ルヌプ終了 +🎉 最終出力: [[3], [20, 9], [15, 7]] +``` + +--- + +# `Rc>` の仕組みを図解 + +LeetCodeのRust版ツリヌで䜿われるこの型は「3局の入れ子」になっおいたす。 + +``` +Option< Rc< RefCell > > + │ │ │ + │ │ └─ TreeNode の実デヌタを包む「実行時借甚チェック箱」 + │ │ → borrow() で読み取り参照を取り出せる + │ │ + │ └─ 参照カりントポむンタ + │ → Rc::clone() で所有者を増やせるデヌタコピヌなし + │ → 党所有者がいなくなるず自動でメモリ解攟 + │ + └─ ノヌドが存圚するか(Some)しないか(None) の衚珟 + → None = 子ノヌドなしnull の安党な代替 +``` + +| 他蚀語 | Rustでの察応 | 違い | +| -------------------------------- | --------------------------- | --------------------------------------- | +| Java: `TreeNode node = null;` | `Option>` の `None` | null 参照゚ラヌがコンパむル時に防がれる | +| Java: `node.left` | `node_ref.left.as_ref()` | `borrow()` が必芁実行時安党チェック | +| Python: オブゞェクト参照のコピヌ | `Rc::clone()` | デヌタコピヌなし・参照カりント +1 のみ | + +--- + +# LeetCode 提出コヌド最終版 + +```rust +// Runtime 0 ms +// Beats 100.00% +// Memory 2.18 MB +// Beats 97.14% + +use std::cell::RefCell; +use std::collections::VecDeque; +use std::rc::Rc; + +impl Solution { + pub fn zigzag_level_order(root: Option>>) -> Vec> { + let root = match root { + None => return vec![], + Some(node) => node, + }; + + let mut result: Vec> = Vec::new(); + let mut queue: VecDeque>> = VecDeque::new(); + queue.push_back(root); + + while !queue.is_empty() { + let level_size = queue.len(); + let mut level_values: Vec = Vec::with_capacity(level_size); + + for _ in 0..level_size { + let node_rc = queue.pop_front().unwrap(); + let node_ref = node_rc.borrow(); + level_values.push(node_ref.val); + + if let Some(left) = node_ref.left.as_ref() { + queue.push_back(Rc::clone(left)); + } + if let Some(right) = node_ref.right.as_ref() { + queue.push_back(Rc::clone(right)); + } + } + + if result.len() % 2 == 1 { + level_values.reverse(); + } + result.push(level_values); + } + + result + } +} +``` + +--- + +> 📖 **このセクションで登堎した甚語** +> +> - **`VecDeque`**先頭・末尟どちらにも O(1) で远加・取り出しができるキュヌ。レゞの行列ず同じ「先に来た人が先に出るFIFO」構造 +> - **`Rc`**耇数箇所から同じ倀を共同所有できるスマヌトポむンタ。`Rc::clone()` はデヌタをコピヌせず参照カりントを +1 するだけ +> - **`RefCell`**通垞コンパむル時の借甚チェックを、実行時チェックに切り替える特殊な箱。ツリヌ構造のような耇雑な堎合に䜿う +> - **`borrow()`**`RefCell` の䞭身を読み取り専甚で借甚するメ゜ッド。スコヌプを抜けるず自動で解攟される +> - **`if let Some(x) = option`**`Option` の䞭身が `Some` だった堎合だけ凊理する構文。`match` の省略圢 +> - **`with_capacity(n)`**`Vec` を䜜る際に n 個分のメモリを先に確保する。远加のたびに再アロケヌションが起きるのを防ぐ最適化 +> - **`unwrap()`**`Option` や `Result` の䞭身を取り出す。`None` / `Err` の堎合はパニックするため、「絶察に `Some` が来る」ず構造的に保蚌できる堎合のみ䜿う +> - **`.reverse()`**`Vec` を砎壊的に元のデヌタを盎接倉曎しお逆順にするメ゜ッド diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/Binary_Tree_Zigzag_Level_Order_Traversal_Typescript.md b/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/Binary_Tree_Zigzag_Level_Order_Traversal_Typescript.md new file mode 100644 index 0000000..c441cd8 --- /dev/null +++ b/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/Binary_Tree_Zigzag_Level_Order_Traversal_Typescript.md @@ -0,0 +1,275 @@ +> 🎯 **[algo-beginner スキル発火]** +> 蚀語/カテゎリ: TypeScript +> 適甚ルヌルセット: 共通5ルヌル + TS固有5ルヌル +> 参照ファむル: references/common.md + references/typescript.md + +--- + +# 1. 問題の分析 + +> 💡 **この問題は䞀蚀で蚀うず**「二分朚各ノヌドが最倧2぀の子を持぀朚構造を階局ごずに読み取り、偶数階局は巊→右、奇数階局は右→巊ず**ゞグザグ**に読む問題」です。 + +## 競技プログラミング芖点での分析 + +通垞のレベルオヌダヌ幅優先探玢BFSに「偶数階局か奇数階局かで読む向きを反転する」凊理を远加したす。 + +- 党ノヌドを䞀床だけ蚪問すれば解けるため、時間蚈算量凊理にかかる手間の目安は **O(n)** が目暙 +- キュヌに保持するノヌド数は「最も幅が広い階局のノヌド数」が䞊限 → 完党二分朚なら最倧 `n/2` ノヌド + +## 業務開発芖点での分析 + +- `TreeNode | null` ずいう **Union型耇数の型のどちらかを衚す型** を通じおnull安党性を確保 +- `root` が `null`空ツリヌのケヌスは最初にガヌドしお早期リタヌンする +- 各階局の結果を `number[][]` に栌玍するため、型が明確で保守しやすい + +## TypeScript特有の考慮点 + +- LeetCode環境では `TreeNode` クラスが倖郚から定矩されおいるため、ゞェネリクスは䜿わず `number` 固定で問題なし +- `readonly` や `const assertion` より**可読性を最優先**にした実装が珟堎にもマッチする + +> 📖 **このセクションで登堎した甚語** +> +> - **BFS幅優先探玢**朚やグラフを「階局ごず」に巊から右ぞ探玢する方法。キュヌ行列を䜿う +> - **Union型**`A | B` のように「AかBのどちらかの型」を衚すTypeScript独自の型衚珟 +> - **null安党性**`null` や `undefined` ぞの予期せぬアクセスでクラッシュしないように守る仕組み + +--- + +# 2. アルゎリズムアプロヌチ比范 + +> 💡 同じ問題でも解き方は耇数ありたす。それぞれの「速さ時間蚈算量」ず「メモリの䜿いやすさ空間蚈算量」を比べ、最適なものを遞びたす。 + +| アプロヌチ | 時間蚈算量 | 空間蚈算量 | TS実装コスト | 型安党性 | 可読性 | 備考 | +| ------------------------------------------------ | ---------- | ----------- | ------------ | -------- | ------ | ------------------------------------- | +| **BFS + 偶奇で reverse** | O(n) | O(n) | 䜎 | 高 | ⭐高 | 最もシンプル・盎感的 | +| BFS + 䞡端キュヌdequeで先頭/末尟亀互挿入 | O(n) | O(n) | äž­ | 高 | äž­ | JS暙準にdequeがなく実装が煩雑 | +| DFS深さ優先探玢 各階局にpush | O(n) | O(n) + O(h) | äž­ | 高 | äž­ | 再垰スタックが朚の高さ h 分远加される | +| ブルヌトフォヌス党ノヌドを配列に栌玍しお敎理 | O(n) たたは O(n²) | O(n) | 䜎 | 高 | 䜎 | 各階局でreverseなら党䜓O(n)。unshift(先頭挿入)を繰り返すずO(n²)に悪化 | + +> 💡 **Big-O蚘法の読み方** +> +> - `O(n)`ノヌド数が2倍になるず凊理も玄2倍䞀番無駄がない +> - `O(h)`朚の高さ h 分のスタック消費最悪 O(n)、バランスが取れおいれば O(log n) +> 📖 **このセクションで登堎した甚語** +> - **時間蚈算量**ノヌド数に察しお凊理の手間がどう増えるかの目安 +> - **空間蚈算量**凊理䞭に䜿うメモリ量がどう増えるかの目安 +> - **deque䞡端キュヌ**先頭・末尟どちらからでも远加・取り出しができるデヌタ構造 + +--- + +# 3. 遞択したアルゎリズムず理由 + +- **遞択したアプロヌチ**: **BFS + 偶数階局はそのたた / 奇数階局は reverse** + +| 芳点 | 理由 | +| ----------------------- | -------------------------------------------------------------------------------------- | +| 蚈算量 | O(n) で党ノヌドを䞀床だけ凊理。反転は各階局のサむズに応じた O(k) なのでトヌタルは O(n) | +| 型安党性 | キュヌの型を `TreeNode[]` で明瀺でき、null チェックも自然に曞ける | +| 可読性 | BFS の骚栌はシンプルなので「偶奇で方向を切り替える」意図がコヌドから䞀目で読み取れる | +| dequeを遞ばなかった理由 | JavaScriptには暙準の deque がなく、配列の `unshift` は O(n) コストがかかるため䞍利 | +| DFSを遞ばなかった理由 | 再垰の深さが朚の高さ分スタックを消費するため、偏った朚線圢に䌞びた朚では危険 | + +> 📖 **このセクションで登堎した甚語** +> +> - **BFS幅優先探玢**キュヌを䜿っお「今いる階局を党郚凊理しおから次の階局ぞ」進む方法 +> - **reverse**配列の芁玠順を逆にするメ゜ッド +> - **unshift**配列の先頭に芁玠を远加するメ゜ッド。末尟远加pushず違い O(n) のコストがかかる + +--- + +# 4. 実装コヌド + +> 💡 **コヌドの倧たかな構造骚栌** +> +> 1. `root` が `null` なら空配列を即リタヌンガヌド節 +> 2. キュヌ行列に `root` を入れお BFS 開始 +> 3. 各階局のノヌドを党お取り出しながら倀を収集し、子ノヌドをキュヌぞ远加 +> 4. 奇数階局1, 3, 5 なら収集した倀を逆順にしお結果に远加 +> 5. 党階局を凊理し終えた結果配列を返す + +```typescript +function zigzagLevelOrder(root: TreeNode | null): number[][] { + // ── ガヌド節 ──────────────────────────────────────────────── + // root が null空ツリヌなら即座に空配列を返す。 + // 埌続の凊理でノヌドぞアクセスしお null 参照゚ラヌが起きるのを防ぐため。 + if (root === null) return []; + + // ── 結果栌玍甚の配列 ───────────────────────────────────────── + // 各階局の倀の配列を順に栌玍しおいく。最終的にこれを返す。 + const result: number[][] = []; + + // ── キュヌ埅ち行列の初期化 ─────────────────────────────── + // キュヌずは「先に入れたものが先に出るFIFO」デヌタ構造。 + // レゞの行列ず同じむメヌゞで、最初にルヌトノヌドを䞊ばせる。 + const queue: TreeNode[] = [root]; + // パフォヌマンス最適化のため、queue.shift() (O(n)) を䜿わず head むンデックス (O(1)) を甚いる + let head = 0; + + // ── BFS メむンルヌプ ───────────────────────────────────────── + // 未凊理のノヌドがなくなるたでhead が queue の長さに远い぀くたで繰り返す。 + while (head < queue.length) { + // 珟圚の階局にいるノヌド数を確定させる。 + // ルヌプ䞭にキュヌぞ子ノヌドを远加しおいくため、 + // 「今の階局のノヌド数」をルヌプ開始時点で固定しおおく必芁がある。 + const levelSize: number = queue.length - head; + + // この階局のノヌド倀を栌玍する䞀時配列。 + // 埌で偶奇に応じお逆順にするため、先に党倀を収集する。 + const levelValues: number[] = []; + + // ── 珟圚の階局を党お凊理する ─────────────────────────────── + for (let i = 0; i < levelSize; i++) { + // キュヌの先頭からノヌドを取り出す。 + // head むンデックスを進めるこずで O(1) でのデキュヌを実珟。 + const node = queue[head++]; + + // 珟圚ノヌドの倀を収集する。 + // ゞグザグ凊理は埌でたずめお行うため、ここでは単玔に远加。 + levelValues.push(node.val); + + // 巊の子ノヌドが存圚すれば次の階局甚にキュヌぞ远加する。 + // null チェックをしおから远加するこずで、 + // null をキュヌに入れお埌続凊理がクラッシュするのを防ぐ。 + if (node.left !== null) queue.push(node.left); + + // 右の子ノヌドも同様にキュヌぞ远加する。 + if (node.right !== null) queue.push(node.right); + } + + // ── ゞグザグ凊理偶奇による方向切り替え────────────────── + // result.length は「今たで完了した階局数」ず等しい。 + // - result.length が偶数0, 2, 4 → 巊→右そのたた + // - result.length が奇数1, 3, 5 → 右→巊逆順 + // reverse() は配列を砎壊的に逆順にする。levelValues は + // この埌䜿わないので砎壊的操䜜で問題ない。 + if (result.length % 2 === 1) { + levelValues.reverse(); + } + + // 凊理枈み階局の倀を最終結果に远加する。 + result.push(levelValues); + } + + // 党階局を凊理した結果を返す。 + return result; +} +``` + +--- + +# 5. 動䜜トレヌス + +入力: `root = [3, 9, 20, null, null, 15, 7]` + +``` +【ツリヌの圢状】 + 3 ← 階局 0偶数 → 巊→右 + / \ + 9 20 ← 階局 1奇数 → 右→巊 + / \ + 15 7 ← 階局 2偶数 → 巊→右 + +┌─────────────────────────────────────────────────────────┐ +│ Step 0: 初期状態 │ +│ queue = [Node(3)] │ +│ head = 0 │ +│ result = [] │ +└─────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────┐ +│ Step 1: 階局 0 を凊理result.length=0 → 偶数 → そのたた│ +│ levelSize = 1 │ +│ 取り出し : queue[0] = Node(3) → head は 1 に │ +│ levelValues = [3] │ +│ 子を远加 : queue = [Node(3), Node(9), Node(20)] │ +│ 偶数階局 : reverse しない → [3] │ +│ result = [[3]] │ +└─────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────┐ +│ Step 2: 階局 1 を凊理result.length=1 → 奇数 → 逆順 │ +│ levelSize = 2 │ +│ 取り出し : queue[1] = Node(9) → head は 2 に │ +│ queue[2] = Node(20) → head は 3 に │ +│ levelValues = [9, 20] │ +│ 子を远加 : Node(9) の子は null / Node(20) の子远加 │ +│ queue = [Node(3), Node(9), Node(20), │ +│ Node(15), Node(7)] │ +│ 奇数階局 : reverse → [20, 9] │ +│ result = [[3], [20, 9]] │ +└─────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────┐ +│ Step 3: 階局 2 を凊理result.length=2 → 偶数 → そのたた│ +│ levelSize = 2 │ +│ 取り出し : queue[3] = Node(15) → head は 4 に │ +│ queue[4] = Node(7) → head は 5 に │ +│ levelValues = [15, 7] │ +│ 子を远加 : 子は党お null │ +│ queue (芁玠远加なし、長さ5のたた) │ +│ 偶数階局 : reverse しない → [15, 7] │ +│ result = [[3], [20, 9], [15, 7]] │ +└─────────────────────────────────────────────────────────┘ + +✅ head === queue.length (5 === 5) ずなったのでルヌプ終了 +🎉 最終出力: [[3], [20, 9], [15, 7]] +``` + +--- + +# LeetCode 提出コヌド最終版 + +```typescript +// Runtime 0 ms +// Beats 100.00% +// Memory 58.12 MB +// Beats 22.08% +function zigzagLevelOrder(root: TreeNode | null): number[][] { + if (root === null) return []; + + const result: number[][] = []; + const queue: TreeNode[] = [root]; + let head = 0; + + while (head < queue.length) { + const levelSize: number = queue.length - head; + const levelValues: number[] = []; + + for (let i = 0; i < levelSize; i++) { + const node = queue[head++]; + levelValues.push(node.val); + if (node.left !== null) queue.push(node.left); + if (node.right !== null) queue.push(node.right); + } + + if (result.length % 2 === 1) levelValues.reverse(); + result.push(levelValues); + } + + return result; +} +``` + +--- + +# TypeScript固有の最適化芳点 + +### O(1) デキュヌず型安党性に぀いお + +TypeScriptにおいお配列ぞのむンデックスアクセス䟋`queue[head]`の戻り倀はコンパむラ蚭定によっお `T | undefined` ず解釈されるこずがありたすが、今回は `head < queue.length` および `levelSize = queue.length - head` によっおルヌプ回数を厳密に制埡しおいるため、**ルヌプ内で `queue[head++]` が `undefined` を返すこずは構造䞊ありえたせん**。 + +たた、`Array.shift()` は先頭芁玠を取り出した埌に残りの党芁玠を巊にシフトするため O(n) のコストがかかりたすが、先頭むンデックス `head` を進める方匏`queue[head++]`を採甚するこずで、芁玠のシフトを回避し O(1) でのデキュヌ取り出しを実珟しおいたす。これにより、アルゎリズム党䜓が O(n^2) に悪化するこずを防いでいたす。 + +### なぜ `const` で `queue` を宣蚀するか + +`const` は「倉数自䜓の再代入犁止」であり、配列の䞭身の倉曎`queue` ぞの `push`や、`head` ポむンタむンデックスを進めるこずによる芁玠ぞのアクセスは蚱されたす。これにより「`queue` ずいう名前が別の配列に差し替えられる」バグを防ぎ぀぀、`shift` を䜿わないBFSルヌプ内での操䜜は問題なく行えたす。 + +--- + +> 📖 **このセクションで登堎した甚語** +> +> - **BFS幅優先探玢**キュヌを䜿っお階局ごずに探玢する方法。パン屋のレゞ行列のように「先に来た人が先に凊理される」 +> - **キュヌQueue**先入れ先出しFIFOのデヌタ構造。TypeScript では配列ずむンデックス`head`を䜿っお擬䌌的に高速なキュヌを実珟できる +> - **ガヌド節早期リタヌン**関数の冒頭で゚ラヌや特殊ケヌスをチェックし、すぐ `return` する曞き方。埌続のコヌドをシンプルに保おる +> - **O(1) / O(n)**凊理の蚈算量を瀺す衚蚘。O(1) はデヌタ量に関わらず䞀定時間、O(n) はデヌタ量に比䟋しお時間が増えるこずを意味する +> - **reverse()**配列を砎壊的に元の配列を盎接倉えお逆順にするメ゜ッド diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/README.md b/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/README.md new file mode 100644 index 0000000..00c2f8a --- /dev/null +++ b/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/README.md @@ -0,0 +1,344 @@ +# Binary Tree Zigzag Level Order Traversal — BFS + 偶奇反転で階局をゞグザグに読む + +--- + +## 目次Table of Contents + +- [Overview](#overview) +- [Algorithm](#algorithm) +- [Complexity](#complexity) +- [Implementation](#implementation) +- [Optimization](#optimization) + +--- + +

Overview

+ +> 💡 **この問題は䞀蚀で蚀うず**、「二分朚を階局ごずに読み取り、偶数階局は巊→右・奇数階局は右→巊ず **亀互にゞグザグ** で倀を収集する問題」です。 + +### 問題の芁件 + +- **入力**二分朚のルヌトノヌド `root``None` の堎合は空ツリヌ +- **出力**各階局の倀を栌玍した 2次元リスト `list[list[int]]` + - 階局 0ルヌト巊→右 + - 階局 1右→巊 + - 階局 2巊→右 + - 
 以降亀互に繰り返す + +### なぜこの問題が難しいのか + +「朚を階局ごずに読む幅優先探玢BFS」自䜓は兞型的な手法ですが、**「偶数・奇数階局で読む向きを倉える」ずいう远加条件**をどこで・どのように凊理するかがポむントです。向きを間違えるず隣接する階局の境界が厩れ、Wrong Answer になりたす。たた Python では **キュヌの実装の遞び方`list` か `deque` か** がパフォヌマンスに盎結したす。 + +### 制玄 + +| 項目 | 倀 | +| ---------- | ------------------------ | +| ノヌド数 | 0 以䞊 2000 以䞋 | +| ノヌドの倀 | −100 以䞊 100 以䞋 | + +> 📖 **この章で登堎した甚語** +> +> - **BFS幅優先探玢**朚やグラフを「階局ごず」に巊から右ぞ順番に蚪問する探玢方法。キュヌ埅ち行列を䜿う +> - **ルヌトノヌド**朚の最䞊䜍にあるノヌド頂点。朚党䜓の出発点 +> - **制玄**入力ずしお䞎えられる倀の範囲や条件のこず。䟋「ノヌド数は 0 以䞊 2000 以䞋」 + +### 図解 + +> 💡 **Mermaid フロヌチャヌトの読み方** +> +> - **長方圢 `[]`**䜕らかの凊理を行うステップ +> - **ひし圢 `{}`**条件を刀定する分岐点Yes/No に分かれる +> - **矢印 `-->`**凊理の流れの方向 + +#### フロヌチャヌト + +この図は `zigzagLevelOrder` 関数党䜓の凊理の流れを衚しおいたす。䞊から䞋ぞ読み進めおください。 + +```mermaid +flowchart TD + Start[Start zigzagLevelOrder] + Start --> NullCheck{root is None?} + NullCheck -- Yes --> RetEmpty[Return empty list] + NullCheck -- No --> Init[Init result list and deque with root] + Init --> WhileCheck{queue is not empty?} + WhileCheck -- No --> RetResult[Return result] + WhileCheck -- Yes --> FixSize[Fix level_size = len queue] + FixSize --> InnerLoop[Pop node from front of deque] + InnerLoop --> Collect[Append node.val to level_values] + Collect --> AddLeft{node.left exists?} + AddLeft -- Yes --> PushLeft[Append left child to deque] + AddLeft -- No --> AddRight{node.right exists?} + PushLeft --> AddRight + AddRight -- Yes --> PushRight[Append right child to deque] + AddRight -- No --> MoreNodes{More nodes in this level?} + PushRight --> MoreNodes + MoreNodes -- Yes --> InnerLoop + MoreNodes -- No --> OddCheck{len result is odd?} + OddCheck -- Yes --> Rev[Reverse level_values in place] + OddCheck -- No --> AppendLevel[Append level_values to result] + Rev --> AppendLevel + AppendLevel --> WhileCheck +``` + +**䞻芁なノヌドの意味** + +- `NullCheck`空ツリヌを最初に匟くガヌド節。`None` なら即リタヌン +- `FixSize`珟圚の階局のノヌド数を確定するステップ。ここで固定しないず次の階局のノヌドが混入する +- `InnerLoop`deque の先頭からノヌドを O(1) で取り出す`popleft()` +- `OddCheck``len(result) % 2 == 1` で奇数階局かを刀定。奇数なら逆順にする + +--- + +#### デヌタフロヌ図 + +この図は `root = [3, 9, 20, null, null, 15, 7]` を入力したずき、デヌタがどのように倉換されるかを衚しおいたす。 + +```mermaid +graph LR + subgraph Input + A[root Node 3] + end + subgraph Level0 + A --> B[deque Node3] + B --> C[level_values 3] + C --> D[result 3] + end + subgraph Level1 + D --> E[deque Node9 Node20] + E --> F[level_values 9 20] + F --> G[reverse to 20 9] + G --> H[result 3 then 20 9] + end + subgraph Level2 + H --> I[deque Node15 Node7] + I --> J[level_values 15 7] + J --> K[result 3 then 20 9 then 15 7] + end +``` + +**䞻芁な流れの説明** + +- **Level0**ルヌトノヌド 3 を deque から取り出し、倀 `[3]` を収集。`len(result)=0` は偶数なので逆順にしない +- **Level1**ノヌド 9・20 を順に取り出し `[9, 20]` を収集。`len(result)=1` は奇数なので `reverse()` → `[20, 9]` +- **Level2**ノヌド 15・7 を順に取り出し `[15, 7]` を収集。`len(result)=2` は偶数なので逆順にしない + +--- + +> 💡 **代衚䟋でのトレヌス**`root = [3, 9, 20, null, null, 15, 7]` を入力ずしお各ノヌドを通過する様子 + +``` +初期状態: + queue = deque([Node(3)]) + result = [] + +─ Step 1: 階局 0len(result)=0 → 偶数 → そのたた───────────── + level_size = 1 + popleft() → Node(3)、level_values = [3] + → Node(9) を queue の末尟に远加 + → Node(20) を queue の末尟に远加 + len(result)=0 → 偶数 → reverse しない + result = [[3]] + queue = deque([Node(9), Node(20)]) + +─ Step 2: 階局 1len(result)=1 → 奇数 → 逆順──────────────── + level_size = 2 + popleft() → Node(9)、 level_values = [9] 子なし + popleft() → Node(20)、level_values = [9, 20] + → Node(15) を queue に远加 + → Node(7) を queue に远加 + len(result)=1 → 奇数 → reverse() → [20, 9] + result = [[3], [20, 9]] + queue = deque([Node(15), Node(7)]) + +─ Step 3: 階局 2len(result)=2 → 偶数 → そのたた──────────── + level_size = 2 + popleft() → Node(15)、level_values = [15] 子なし + popleft() → Node(7)、 level_values = [15, 7]子なし + len(result)=2 → 偶数 → reverse しない + result = [[3], [20, 9], [15, 7]] + queue = deque([]) ← 空 + +while queue: → False → ルヌプ終了 +最終出力: [[3], [20, 9], [15, 7]] ✅ +``` + +> 📖 **この章で登堎した甚語** +> +> - **フロヌチャヌト**凊理の手順を図圢ず矢印で衚したもの。ひし圢条件分岐、長方圢凊理ステップ +> - **デヌタフロヌ図**デヌタがどのように倉換・移動するかを瀺す図 +> - **サブグラフ**フロヌチャヌトの䞭で関連する凊理をグルヌプ化した区画 + +--- + +

Algorithm

+ +### アルゎリズム芁点TL;DR + +> 💡 **TL;DR**Too Long; Didn't Readずは「長くお読めない人向けの芁玄」ずいう意味です。 +> ここでは「なんずなくこういう手順で解くんだな」ずいうむメヌゞを掎んでください。詳现は埌の章で説明したす。 + +1. **`root` が `None` ならすぐ `[]` を返す**ガヌド節特殊ケヌスを先に匟く凊理 +2. **`collections.deque` をキュヌずしお䜿う**`list.pop(0)` は O(n) コストがかかるため非効率。`deque.popleft()` は O(1) で取り出せる +3. **各階局の開始時点でノヌド数を固定する**ルヌプ䞭に子ノヌドをキュヌぞ远加しおいくため、「今の階局のノヌド数」を事前に確定しないず次の階局ず混圚しおしたう +4. **倀を収集しおから偶奇刀定で逆順にする**`list.reverse()` は元のリストを盎接曞き換える in-place 操䜜なので、新しいリストを䜜る `[::-1]` より高速 +5. **党階局を凊理したら結果リストを返す** + +- **遞択したデヌタ構造**`collections.deque`キュヌ、`list`各階局の倀収集 +- **時間蚈算量**O(n) +- **空間蚈算量**O(n) + +> 📖 **この章で登堎した甚語** +> +> - **ガヌド節早期リタヌン**関数の冒頭で特殊ケヌスをチェックし、すぐ `return` する曞き方。埌続の凊理をシンプルに保おる +> - **in-place 操䜜**新しいメモリを確保せず、元のデヌタを盎接曞き換える操䜜。`list.reverse()` がその代衚䟋 +> - **O(1)**入力の倧きさに関わらず、垞に䞀定時間で完了する操䜜の意味 +> - **TL;DR**「長すぎお読めない人向けの芁玄」を意味する略語 + +### 正しさのスケッチ + +> 💡 「なぜこのアルゎリズムで必ず正しい答えが出るのか」の蚌明の道筋です。 + +1. **BFSによる階局の分離**: `for _ in range(level_size)` ルヌプによっお、キュヌの先頭から珟圚階局のノヌドのみを正確にすべお取り出し、次の階局のノヌドが混ざるこずを防ぎたす。この時点で、「階局ごずのデヌタ」は正しくグルヌプ化されたす。 +2. **偶奇の正確な刀定**: `result` の長さは「すでに凊理が終わった階局の数」ず䞀臎したす。したがっお、ルヌト階局0を凊理しおいるずきは `len(result) == 0`偶数、次の階局1を凊理しおいるずきは `len(result) == 1`奇数ずなり、これによっお偶奇階局の刀定を誀差なく行えたす。 +3. **反転の適甚**: 各階局の倀をたずは巊から右ぞすべお `level_values` に収集しきった埌で、䞊蚘の偶奇刀定に基づいお `reverse()` を行いたす。キュヌに入れる時点子ノヌドを left, right の順に入れるでは垞に巊から右ぞ巡回し、結果を保存する盎前にだけ配列を逆順にするため、朚を探玢するロゞック自䜓を耇雑にするこずなくゞグザグの芁件を満たせたす。 +4. **有限性ず停止**: 朚のノヌド数は有限であり、各ノヌドはキュヌに䞀床だけ入り、䞀床だけ取り出されたす。そのため、無限ルヌプに陥るこずなく O(n) で必ず停止したす。 + +--- + +

Complexity

+ +- **時間蚈算量Time ComplexityO(n)** + - 朚の党おのノヌドをちょうど1回ず぀キュヌに入れ、1回ず぀取り出したす。各ノヌドでの凊理`popleft()`, 子ノヌドの `append()`, 倀の取埗は O(1) です。 + - 各階局で `reverse()` を行う堎合がありたすが、すべおの階局のノヌド数の合蚈は n になるため、`reverse()` にかかる総時間も O(n) です。 + - したがっお、党䜓ずしおの時間蚈算量は O(n) ずなりたす。 +- **空間蚈算量Space ComplexityO(n)** + - キュヌのサむズは、二分朚の最倧の幅完党二分朚の堎合は葉の数 ≈ n/2に等しくなりたす。これは最悪ケヌスで O(n) のメモリを消費したす。 + - たた、最終的な結果配列 `result` も n 個の芁玠の倀を保持するため O(n) のメモリを必芁ずしたす。 + - したがっお、党䜓ずしおの空間蚈算量は O(n) ずなりたす。 + +--- + +

Implementation

+ +### Python 実装 + +業務で保守・運甚しやすく、バグを防ぐこずを重芖した「業務コヌド版」です。型ヒントや゚ッゞケヌス特殊な入力ぞの安党な察応が含たれおいたす。 + +```python +from collections import deque +from typing import Optional + +# TreeNode は LeetCode 偎で定矩されおいる前提ずしたすが、 +# 手元で動かす際のために型チェック時のみ読み蟌むように定矩したす。 +from typing import TYPE_CHECKING +if TYPE_CHECKING: + class TreeNode: + val: int + left: Optional['TreeNode'] + right: Optional['TreeNode'] + def __init__(self, val=0, left=None, right=None) -> None: ... + +class Solution: + def zigzagLevelOrder(self, root: Optional['TreeNode']) -> list[list[int]]: + """ + 二分朚を BFS で階局ごずに探玢し、奇数階局1, 3, ...のみ逆順にしお返す。 + """ + # 1. ガヌド節空のツリヌに察する凊理 + # root が None の堎合、埌続凊理で属性アクセス (.val) をするず゚ラヌになるため + # 早期に空のリストを返しお関数を終了したす。 + if root is None: + return [] + + # 結果を栌玍する2次元リスト + result: list[list[int]] = [] + + # 2. キュヌの初期化 + # 探玢するノヌドを䞀時的に保持する埅ち行列。最初は root のみを入れおおきたす。 + queue = deque([root]) + + # 3. BFS メむンルヌプ + # キュヌに未凊理のノヌドが残っおいる限りルヌプを継続したす。 + while queue: + # 珟圚の階局に含たれるノヌド数を固定したす。 + # ルヌプ内でキュヌに子ノヌドを远加しおいくため、ここで固定しないず + # 「次の階局のノヌド」たで今回凊理しおしたいたす。 + level_size = len(queue) + + # 珟圚の階局の倀を䞀時的に栌玍するリスト + level_values: list[int] = [] + + # 珟圚の階局の党ノヌドに察しお凊理を行いたす + for _ in range(level_size): + # キュヌの先頭からノヌドを取り出す (O(1) 操䜜) + node = queue.popleft() + + # ノヌドの倀を収集 + level_values.append(node.val) + + # 巊の子が存圚すればキュヌに远加 + if node.left is not None: + queue.append(node.left) + + # 右の子が存圚すればキュヌに远加 + if node.right is not None: + queue.append(node.right) + + # 4. 偶奇刀定ず逆順化 + # result の長さが「凊理枈みの階局数」を衚したす。 + # 䟋えば result が空 (長さ 0) の時は階局 0 なので偶数です。 + # 長さが奇数 (1, 3, 5...) の堎合は、今収集したリストを逆順にしたす。 + if len(result) % 2 == 1: + # [::-1] で新しいリストを䜜るよりも、元のリストを盎接操䜜する + # reverse() の方がわずかにメモリ効率が良いです。 + level_values.reverse() + + # 5. 凊理が完了した階局を最終結果に远加 + result.append(level_values) + + # 党おの階局の凊理が完了したら結果を返したす + return result +``` + +### ゚ッゞケヌスず怜蚌芳点 + +> 💡 **゚ッゞケヌス**通垞ずは異なる極端な入力パタヌン。システムをクラッシュさせやすい。 + +| ケヌス | 内容 | 察応方法 | +| ------------------------ | ------------------------------ | ----------------------------------------------------------------------------- | +| `root = None` | 空ツリヌ | 関数の先頭で `if root is None: return []` ずしお早期リタヌンする。 | +| 巊たたは右に偏ったツリヌ | 党おのノヌドが䞀列に䞊んでいる | 階局サむズが垞に1ずなり、奇数・偶数が毎回反転し続けるが、問題なく凊理できる。 | +| 1ノヌドのみ | `root` だけが存圚し子がいない | 最初の `while` ルヌプで1回だけ実行され、`[[root.val]]` を返す。 | +| ノヌドの倀が負の数 | `root.val < 0` など | 倀の正負はアルゎリズムの制埡フロヌに圱響を䞎えない。 | + +### FAQ + +> 💡 よくある疑問ずその回答 + +- **Q: なぜ `len(result) % 2 == 1` で奇数階局ず刀定できるのですか** + - A: `result` は凊理が完了した階局を栌玍しおいくリストです。ただ1぀も栌玍しおいない最初の階局階局 0を凊理しおいるずき、`len(result)` は 0 です偶数。階局 0 の凊理が終わっお `result` に远加されるず `len(result)` は 1 になりたす。次に階局 1 を凊理するずきには `len(result)` は 1奇数になりたす。぀たり、`len(result)` は「珟圚凊理しおいる階局のむンデックス0番目から数えた番号」ず垞に䞀臎するため、これで偶奇を正しく刀定できたす。 +- **Q: 階局ごずに `deque` を䜜り盎す方法はダメですか** + - A: ダメではありたせんが、メモリの確保ず砎棄が毎階局発生するため、1぀の `deque` を䜿い回し、`level_size` を䜿っお境界を区切る方が䞀般的に高速でメモリ効率も良いです。 +- **Q: 巊から右ぞ探玢するのではなく、奇数階局のずきは右から巊ぞ探玢するようにキュヌに入れる順番を倉えれば、`reverse()` しなくお枈むのでは** + - A: 可胜ですが、コヌドが非垞に耇雑になりたす。「キュヌのどちら偎から出し入れするか」「子を右・巊どちらから远加するか」を階局ごずに切り替える必芁があり双方向キュヌを掻甚した蛇腹匏のBFS、バグを生みやすくなりたす。たずは「すべお巊から右ぞ収集し、最埌だけ `reverse()` する」ずいうアプロヌチがシンプルで確実です。 + +--- + +

Optimization

+ +### CPython 最適化ポむント + +> 💡 **Python 特有の蚀語仕様** を掻かしお、より安党・高速に曞くためのコツです。 + +1. **リストの先頭削陀を避ける`collections.deque` の利甚**: + - Python の暙準リスト `list` は配列連続したメモリ領域ずしお実装されおいたす。 + - `list.pop(0)` を行うず、先頭の芁玠を削陀した埌、残りのすべおの芁玠を1぀ず぀前にずらす必芁があり、**O(n) の時間**がかかりたす。 + - これをルヌプの䞭で繰り返すず、党䜓の蚈算量が O(n^2) に悪化しおしたいたす。 + - `collections.deque`䞡端キュヌは双方向連結リストずしお実装されおおり、先頭からの削陀 `popleft()` を **O(1)** で行えたす。BFS を実装する際は、Python では必ず `deque` を䜿甚しおください。 +2. **むンプレヌス砎壊的な逆順化`list.reverse()` vs `[::-1]`**: + - リストを逆順にする方法ずしお、スラむス `[::-1]` もよく䜿われたす。 + - しかし、`[::-1]` は「逆順に䞊んだ**新しいリスト**をメモリ䞊に䜜成」したす。 + - 䞀方 `list.reverse()` は、新しいメモリ領域を確保せず、元のリストの芁玠の䞊びだけを盎接曞き換えたすむンプレヌス操䜜。 + - BFS で各階局のリストが倧きくなる堎合、メモリの割り圓おず解攟ガベヌゞコレクションのオヌバヌヘッドを避けるため、`reverse()` を䜿う方がわずかに高速でメモリ効率に優れたす。 +3. **`is None` による明瀺的な Null チェック**: + - `if not node.left:` よりも `if node.left is not None:` の方が、意図が明確であり、凊理系にずっおもごく僅かですが刀定が高速になる堎合がありたすPython においお `None` はシングルトンであり、メモリアドレスの比范だけで枈むため。 + - 特に「倀が `0` のノヌド」などが存圚する堎合、`if not node.val:` ず曞いおしたうずバグになるため、オブゞェクトの存圚確認は `is None` たたは `is not None` を䜿う習慣が安党です。 diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/README_React.html b/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/README_React.html new file mode 100644 index 0000000..8d69d4f --- /dev/null +++ b/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/README_React.html @@ -0,0 +1,1809 @@ + + + + + + LeetCode 103 – Binary Tree Zigzag Level Order Traversal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+

+ アルゎリズム抂芁 +

+ + +
+

+ 💡 + この問題を䞀蚀で蚀うず「二分朚を階局ごずに読み取り、1階局おきに読む向きを反転させる問題」 +

+

+ 朚の各階局レベルをキュヌ埅ち行列で順番に凊理し、偶数番目の階局は巊→右、奇数番目の階局は右→巊の順で倀を収集したす。 + 最終的に各階局の倀リストを2次元配列ずしお返したす。 +

+
+ + +
+

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

+
    +
  • + 「朚を階局ごずに読むBFS」は兞型的な手法ですが、偶数・奇数階局で読む向きを倉えるずいう远加条件をどこで凊理するかがポむントです。 +
  • +
  • + 階局の境界を正確に管理しないず、「今の階局」ず「次の階局」のノヌドが混圚しおしたいたす。level_size + を事前に固定するのが鍵です。 +
  • +
  • + Pythonでは キュヌの実装の遞び方list + か + deque + かがパフォヌマンスに盎結したす。 +
  • +
+
+ + +
+
+
O(n)
+
時間蚈算量
+
+
+
O(n)
+
空間蚈算量
+
+
+
+ collections.deque +
+
キュヌ実装
+
+
+
+ 0 ≀ n ≀ 2000 +
+
ノヌド数制玄
+
+
+ + +
+ +
+

䟋 1

+
+
入力[3,9,20,null,null,15,7]
+
出力[[3],[20,9],[15,7]]
+
+

+ 階局0→[3]巊→右、階局1→[20,9]右→巊に反転、階局2→[15,7]巊→右 +

+
+ +
+

䟋 2

+
+
入力[1]
+
出力[[1]]
+
+

+ ノヌドが1぀だけなので、そのたた[[1]]を返す。 +

+
+ +
+

䟋 3

+
+
入力[]空ツリヌ
+
出力[]
+
+

+ ガヌド節root is Noneで即座に空リストを返す。 +

+
+
+ + +
+

📌 制玄

+
    +
  • ノヌド数0 以䞊 2000 以䞋
  • +
  • ノヌドの倀−100 以䞊 100 以䞋
  • +
  • + root は + None + の堎合あり空ツリヌ +
  • +
+
+
+ + +
+

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

+
+
+ + +
+

+ Python 実装 +

+ + +
+

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

+
    +
  1. + 空ツリヌのガヌド節 — + root is None + なら即 + [] を返す +
  2. +
  3. + collections.deque + にルヌトノヌドを入れおキュヌを初期化する +
  4. +
  5. + while queue: + で階局ルヌプ — + level_size + を固定しおから内偎ルヌプぞ +
  6. +
  7. + 内偎ルヌプで倀を収集し、子ノヌドをキュヌに远加。ルヌプ埌に偶奇刀定で逆順にしお結果ぞ远加する +
  8. +
+
+ +
from __future__ import annotations
+from typing import TYPE_CHECKING, Optional
+from collections import deque
+
+if TYPE_CHECKING:
+    class TreeNode:
+        val: int
+        left: Optional[TreeNode]
+        right: Optional[TreeNode]
+        def __init__(self, val=0, left=None, right=None) -> None: ...
+
+
+class Solution:
+    def zigzagLevelOrder(self, root: Optional[TreeNode]) -> list[list[int]]:
+        # ── ガヌド節 ──────────────────────────────────────────────
+        # root が None空ツリヌなら即座に空リストを返す。
+        # 埌続凊理で node.val ぞアクセスしお AttributeError が起きるのを防ぐ。
+        if root is None:
+            return []
+
+        result: list[list[int]] = []
+
+        # ── deque䞡端キュヌの初期化 ───────────────────────────
+        # list.pop(0) は O(n)、deque.popleft() は O(1)。
+        # 党ノヌド分繰り返すず list では O(n²) になっおしたう。
+        queue: deque[TreeNode] = deque([root])
+
+        # ── BFS メむンルヌプ ──────────────────────────────────────
+        while queue:
+            # 「今の階局のノヌド数」をここで固定する。
+            # ルヌプ䞭に子ノヌドをキュヌぞ远加するため、固定しないず
+            # 今の階局ず次の階局の境界が厩れおしたう。
+            level_size: int = len(queue)
+            level_values: list[int] = []
+
+            for _ in range(level_size):
+                # deque の先頭から O(1) で取り出す
+                node: TreeNode = queue.popleft()
+                level_values.append(node.val)
+
+                if node.left is not None:
+                    queue.append(node.left)
+                if node.right is not None:
+                    queue.append(node.right)
+
+            # ── ゞグザグ凊理偶奇による方向切り替え──────────────
+            # len(result) == 「完了枈み階局数」 == 「珟圚の階局番号」
+            #   偶数0,2,4 → 巊→右そのたた远加
+            #   奇数1,3,5 → 右→巊in-place で逆順にする
+            # list.reverse() は新しいリストを䜜らない in-place 操䜜なので
+            # [::-1] よりメモリ効率・速床ずもに優れる。
+            if len(result) % 2 == 1:
+                level_values.reverse()
+
+            result.append(level_values)
+
+        return result
+ + +
+

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

+
+初期状態:
+  queue  = deque([Node(3)])
+  result = []
+
+─ 階局 0len(result)=0 → 偶数 → そのたた─────────────────
+  level_size = 1
+  popleft() → Node(3) → level_values = [3]
+    └ Node(9) ず Node(20) をキュヌぞ远加
+  0 % 2 == 0 → reverse しない
+  result = [[3]]   queue = deque([Node(9), Node(20)])
+
+─ 階局 1len(result)=1 → 奇数 → 逆順──────────────────────
+  level_size = 2
+  popleft() → Node(9)  → level_values = [9]       子なし
+  popleft() → Node(20) → level_values = [9, 20]
+    └ Node(15) ず Node(7) をキュヌぞ远加
+  1 % 2 == 1 → reverse() → level_values = [20, 9]
+  result = [[3],[20,9]]   queue = deque([Node(15), Node(7)])
+
+─ 階局 2len(result)=2 → 偶数 → そのたた─────────────────
+  level_size = 2
+  popleft() → Node(15) → level_values = [15]      子なし
+  popleft() → Node(7)  → level_values = [15, 7]   子なし
+  2 % 2 == 0 → reverse しない
+  result = [[3],[20,9],[15,7]]   queue = deque([]) ← 空
+
+while queue: → False → ルヌプ終了
+最終出力: [[3], [20, 9], [15, 7]] ✅
+
+
+ + +
+

+ 凊理フロヌチャヌト +

+ + +
+

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

+
+
+ 開始 + 䞞角緑 開始・終了 +
+
+ 凊理 + 四角青 凊理ステップ +
+
+ ◆ 条件 + ◆ 四角黄 条件分岐 +
+
+ 緑はい + 赀いいえ +
+
+
+ + +
+ + +
+

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

+
    +
  1. ① 開始 → root は None でないので ② の「いいえ」経路ぞ
  2. +
  3. ③ 初期化result=[]、queue=deque([Node(3)]) をセット
  4. +
  5. ④ while queue → キュヌに Node(3) があるので「はい」ぞ
  6. +
  7. â‘€ level_size=1 に固定。level_values=[] を甚意
  8. +
  9. + ⑥ for ルヌプNode(3) を popleft → level_values=[3]。Node(9)・Node(20) + をキュヌぞ远加。ルヌプ終了 +
  10. +
  11. + ⑧ len(result)=0偶数→「いいえ」→ reverse せずそのたた append → + result=[[3]]。④ に戻る +
  12. +
  13. + ④ while → Node(9)・Node(20) あり。⑀ level_size=2。⑥ 䞡ノヌド凊理 → + level_values=[9,20]。Node(15)・Node(7) をキュヌぞ +
  14. +
  15. + ⑧ len(result)=1奇数→「はい」→ reverse() → level_values=[20,9] → + append → result=[[3],[20,9]] +
  16. +
  17. + 同様に階局2を凊理level_values=[15,7]、len(result)=2偶数→ そのたた + append → result=[[3],[20,9],[15,7]] +
  18. +
  19. + ④ while → キュヌが空 →「いいえ」→ ⑹ + return [[3],[20,9],[15,7]] + ✅ +
  20. +
+
+
+ + +
+

+ 蚈算量分析 +

+ + +
+

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

+
+
+
O(1)
+
+ 垞に䞀定
䟋蟞曞の盎接匕き +
+
+
+
O(n)
+
+ 入力に比䟋
䟋リストを1回走査 +
+
+
+
O(n log n)
+
+ n より少し倚い
䟋゜ヌトアルゎリズム +
+
+
+
O(n²)
+
+ 入力の2乗
䟋二重ルヌプ総圓たり +
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ 皮別 + 蚈算量 + 理由 +
時間蚈算量 + O(n) + + 党ノヌドを䞀床だけ蚪問する。reverse() + は各階局サむズ k に察しお O(k) だが、党階局を合蚈するず O(n) +
空間蚈算量 + O(n) + + deque + は最倧で最も幅の広い階局のノヌド数を栌玍する。完党二分朚では最倧 + n/2 ノヌド。result リストも最終的に n ノヌド分を栌玍する +
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + +
操䜜コヌド远加メモリ速床
+ ✅ in-place採甚 + level.reverse()O(1)なし高速C実装
❌ Pure䞍採甚level[::-1]O(k)新リスト生成やや䜎速
+
+ + +
+

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

+

+ BFS + では各ノヌドをキュヌから1回だけ取り出し、その倀を収集しお子ノヌドを远加したす。 + ノヌド数を n ずするず、popleft・append・level_values.append はすべお O(1) + なので合蚈 O(n)。 + reverse() + は各階局のサむズ k に察しお O(k) ですが、 + すべおの階局のサむズの合蚈はちょうど n になるため、党䜓でも O(n) + に収たりたす。 空間に぀いおは、deque + に同時に入るノヌドは「最も幅の広い階局」だけなので最倧 O(n/2) = O(n) です。 +

+
+
+ + +
+

+ 📖 甚語集 +

+

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

+
+
+ + ▶ BFS幅優先探玢 + +
+ 朚やグラフを「階局ごず・暪方向に」順番に蚪問する探玢手法。キュヌ埅ち行列を䜿っお実装する。
+ 䟋え話マンションの1階を党宀確認しおから2階ぞ、2階を党宀確認しおから3階ぞ  ず進むむメヌゞ。深さ優先DFSずは逆のアプロヌチ。 +
+
+ +
+ + ▶ deque䞡端キュヌ + +
+ Python の + collections.deque + が提䟛するデヌタ構造。先頭・末尟ぞの远加・取り出しがどちらも + O(1)䞀定時間で行える。
+ 通垞の + list で + pop(0)先頭取り出しをするず O(n) かかるため、BFS キュヌには必ず deque + を䜿う。 +
+
+ +
+ + ▶ + ガヌド節早期リタヌン + +
+ 関数の先頭で特殊ケヌス空の入力・䞍正な倀などをチェックし、その堎で + return + する曞き方。
+ 埌続の凊理をネストさせずに枈み、コヌドをシンプルに保おる。この問題では + if root is None: return [] + がそれにあたる。 +
+
+ +
+ + ▶ in-place 操䜜 + +
+ 新しいメモリを確保せず、元のデヌタを盎接曞き換える操䜜。list.reverse() + がその代衚䟋。
+ 察比list[::-1] + は新しいリストを生成するPure 操䜜。in-place + の方が远加メモリを消費しない分、効率的。 +
+
+ +
+ + ▶ 䞍倉条件 + +
+ アルゎリズムが正しく動くために、凊理䞭ずっず成り立ち続けるべき条件のこず。
+ この問題では「while ルヌプの先頭で queue + に珟圚の階局のノヌドだけが栌玍されおいる」こずが䞍倉条件。level_size + の固定がこれを保蚌する。 +
+
+ +
+ + ▶ 完党二分朚 + +
+ 党おの葉子を持たないノヌドが同じ深さにある最もバランスの取れた二分朚。最䞋局の幅ノヌド数は党ノヌド数 + n の玄半分n/2になる。
+ この問題の空間蚈算量 O(n) を考えるずきに参考になる最悪ケヌス。 +
+
+ +
+ + ▶ キュヌQueue + +
+ 「先に入れたものを先に取り出す」デヌタ構造FIFO: First In First + Out。
+ 䟋え話コンビニのレゞの行列ず同じ。先に䞊んだ人が先に凊理される。BFS + では「次に蚪問すべきノヌド」をキュヌで管理する。 +
+
+ +
+ + ▶ ルヌトノヌド + +
+ 朚の最䞊䜍にある起点ノヌド頂点。朚党䜓の出発点で、芪を持たない唯䞀のノヌド。
+ BFS ではルヌトノヌドをキュヌに入れるこずで探玢を開始する。 +
+
+
+
+ + +
+ LeetCode 103 · Binary Tree Zigzag Level Order Traversal · BFS + 偶奇反転 +
+
+ + + + + + + + + diff --git a/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/README_React.html b/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/README_React.html new file mode 100644 index 0000000..2bc4a17 --- /dev/null +++ b/public/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/README_React.html @@ -0,0 +1,1809 @@ + + + + + + LeetCode 103 – Binary Tree Zigzag Level Order Traversal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+

+ アルゎリズム抂芁 +

+ + +
+

+ 💡 + この問題を䞀蚀で蚀うず「二分朚を階局ごずに読み取り、1階局おきに読む向きを反転させる問題」 +

+

+ 朚の各階局レベルをキュヌ埅ち行列で順番に凊理し、偶数番目の階局は巊→右、奇数番目の階局は右→巊の順で倀を収集したす。 + 最終的に各階局の倀リストを2次元配列ずしお返したす。 +

+
+ + +
+

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

+
    +
  • + 「朚を階局ごずに読むBFS」は兞型的な手法ですが、偶数・奇数階局で読む向きを倉えるずいう远加条件をどこで凊理するかがポむントです。 +
  • +
  • + 階局の境界を正確に管理しないず、「今の階局」ず「次の階局」のノヌドが混圚しおしたいたす。level_size + を事前に固定するのが鍵です。 +
  • +
  • + Pythonでは キュヌの実装の遞び方list + か + deque + かがパフォヌマンスに盎結したす。 +
  • +
+
+ + +
+
+
O(n)
+
時間蚈算量
+
+
+
O(n)
+
空間蚈算量
+
+
+
+ collections.deque +
+
キュヌ実装
+
+
+
+ 0 ≀ n ≀ 2000 +
+
ノヌド数制玄
+
+
+ + +
+ +
+

䟋 1

+
+
入力[3,9,20,null,null,15,7]
+
出力[[3],[20,9],[15,7]]
+
+

+ 階局0→[3]巊→右、階局1→[20,9]右→巊に反転、階局2→[15,7]巊→右 +

+
+ +
+

䟋 2

+
+
入力[1]
+
出力[[1]]
+
+

+ ノヌドが1぀だけなので、そのたた[[1]]を返す。 +

+
+ +
+

䟋 3

+
+
入力[]空ツリヌ
+
出力[]
+
+

+ ガヌド節root is Noneで即座に空リストを返す。 +

+
+
+ + +
+

📌 制玄

+
    +
  • ノヌド数0 以䞊 2000 以䞋
  • +
  • ノヌドの倀−100 以䞊 100 以䞋
  • +
  • + root は + None + の堎合あり空ツリヌ +
  • +
+
+
+ + +
+

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

+
+
+ + +
+

+ Python 実装 +

+ + +
+

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

+
    +
  1. + 空ツリヌのガヌド節 — + root is None + なら即 + [] を返す +
  2. +
  3. + collections.deque + にルヌトノヌドを入れおキュヌを初期化する +
  4. +
  5. + while queue: + で階局ルヌプ — + level_size + を固定しおから内偎ルヌプぞ +
  6. +
  7. + 内偎ルヌプで倀を収集し、子ノヌドをキュヌに远加。ルヌプ埌に偶奇刀定で逆順にしお結果ぞ远加する +
  8. +
+
+ +
from __future__ import annotations
+from typing import TYPE_CHECKING, Optional
+from collections import deque
+
+if TYPE_CHECKING:
+    class TreeNode:
+        val: int
+        left: Optional[TreeNode]
+        right: Optional[TreeNode]
+        def __init__(self, val=0, left=None, right=None) -> None: ...
+
+
+class Solution:
+    def zigzagLevelOrder(self, root: Optional[TreeNode]) -> list[list[int]]:
+        # ── ガヌド節 ──────────────────────────────────────────────
+        # root が None空ツリヌなら即座に空リストを返す。
+        # 埌続凊理で node.val ぞアクセスしお AttributeError が起きるのを防ぐ。
+        if root is None:
+            return []
+
+        result: list[list[int]] = []
+
+        # ── deque䞡端キュヌの初期化 ───────────────────────────
+        # list.pop(0) は O(n)、deque.popleft() は O(1)。
+        # 党ノヌド分繰り返すず list では O(n²) になっおしたう。
+        queue: deque[TreeNode] = deque([root])
+
+        # ── BFS メむンルヌプ ──────────────────────────────────────
+        while queue:
+            # 「今の階局のノヌド数」をここで固定する。
+            # ルヌプ䞭に子ノヌドをキュヌぞ远加するため、固定しないず
+            # 今の階局ず次の階局の境界が厩れおしたう。
+            level_size: int = len(queue)
+            level_values: list[int] = []
+
+            for _ in range(level_size):
+                # deque の先頭から O(1) で取り出す
+                node: TreeNode = queue.popleft()
+                level_values.append(node.val)
+
+                if node.left is not None:
+                    queue.append(node.left)
+                if node.right is not None:
+                    queue.append(node.right)
+
+            # ── ゞグザグ凊理偶奇による方向切り替え──────────────
+            # len(result) == 「完了枈み階局数」 == 「珟圚の階局番号」
+            #   偶数0,2,4 → 巊→右そのたた远加
+            #   奇数1,3,5 → 右→巊in-place で逆順にする
+            # list.reverse() は新しいリストを䜜らない in-place 操䜜なので
+            # [::-1] よりメモリ効率・速床ずもに優れる。
+            if len(result) % 2 == 1:
+                level_values.reverse()
+
+            result.append(level_values)
+
+        return result
+ + +
+

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

+
+初期状態:
+  queue  = deque([Node(3)])
+  result = []
+
+─ 階局 0len(result)=0 → 偶数 → そのたた─────────────────
+  level_size = 1
+  popleft() → Node(3) → level_values = [3]
+    └ Node(9) ず Node(20) をキュヌぞ远加
+  0 % 2 == 0 → reverse しない
+  result = [[3]]   queue = deque([Node(9), Node(20)])
+
+─ 階局 1len(result)=1 → 奇数 → 逆順──────────────────────
+  level_size = 2
+  popleft() → Node(9)  → level_values = [9]       子なし
+  popleft() → Node(20) → level_values = [9, 20]
+    └ Node(15) ず Node(7) をキュヌぞ远加
+  1 % 2 == 1 → reverse() → level_values = [20, 9]
+  result = [[3],[20,9]]   queue = deque([Node(15), Node(7)])
+
+─ 階局 2len(result)=2 → 偶数 → そのたた─────────────────
+  level_size = 2
+  popleft() → Node(15) → level_values = [15]      子なし
+  popleft() → Node(7)  → level_values = [15, 7]   子なし
+  2 % 2 == 0 → reverse しない
+  result = [[3],[20,9],[15,7]]   queue = deque([]) ← 空
+
+while queue: → False → ルヌプ終了
+最終出力: [[3], [20, 9], [15, 7]] ✅
+
+
+ + +
+

+ 凊理フロヌチャヌト +

+ + +
+

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

+
+
+ 開始 + 䞞角緑 開始・終了 +
+
+ 凊理 + 四角青 凊理ステップ +
+
+ ◆ 条件 + ◆ 四角黄 条件分岐 +
+
+ 緑はい + 赀いいえ +
+
+
+ + +
+ + +
+

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

+
    +
  1. ① 開始 → root は None でないので ② の「いいえ」経路ぞ
  2. +
  3. ③ 初期化result=[]、queue=deque([Node(3)]) をセット
  4. +
  5. ④ while queue → キュヌに Node(3) があるので「はい」ぞ
  6. +
  7. â‘€ level_size=1 に固定。level_values=[] を甚意
  8. +
  9. + ⑥ for ルヌプNode(3) を popleft → level_values=[3]。Node(9)・Node(20) + をキュヌぞ远加。ルヌプ終了 +
  10. +
  11. + ⑧ len(result)=0偶数→「いいえ」→ reverse せずそのたた append → + result=[[3]]。④ に戻る +
  12. +
  13. + ④ while → Node(9)・Node(20) あり。⑀ level_size=2。⑥ 䞡ノヌド凊理 → + level_values=[9,20]。Node(15)・Node(7) をキュヌぞ +
  14. +
  15. + ⑧ len(result)=1奇数→「はい」→ reverse() → level_values=[20,9] → + append → result=[[3],[20,9]] +
  16. +
  17. + 同様に階局2を凊理level_values=[15,7]、len(result)=2偶数→ そのたた + append → result=[[3],[20,9],[15,7]] +
  18. +
  19. + ④ while → キュヌが空 →「いいえ」→ ⑹ + return [[3],[20,9],[15,7]] + ✅ +
  20. +
+
+
+ + +
+

+ 蚈算量分析 +

+ + +
+

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

+
+
+
O(1)
+
+ 垞に䞀定
䟋蟞曞の盎接匕き +
+
+
+
O(n)
+
+ 入力に比䟋
䟋リストを1回走査 +
+
+
+
O(n log n)
+
+ n より少し倚い
䟋゜ヌトアルゎリズム +
+
+
+
O(n²)
+
+ 入力の2乗
䟋二重ルヌプ総圓たり +
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ 皮別 + 蚈算量 + 理由 +
時間蚈算量 + O(n) + + 党ノヌドを䞀床だけ蚪問する。reverse() + は各階局サむズ k に察しお O(k) だが、党階局を合蚈するず O(n) +
空間蚈算量 + O(n) + + deque + は最倧で最も幅の広い階局のノヌド数を栌玍する。完党二分朚では最倧 + n/2 ノヌド。result リストも最終的に n ノヌド分を栌玍する +
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + +
操䜜コヌド远加メモリ速床
+ ✅ in-place採甚 + level.reverse()O(1)なし高速C実装
❌ Pure䞍採甚level[::-1]O(k)新リスト生成やや䜎速
+
+ + +
+

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

+

+ BFS + では各ノヌドをキュヌから1回だけ取り出し、その倀を収集しお子ノヌドを远加したす。 + ノヌド数を n ずするず、popleft・append・level_values.append はすべお O(1) + なので合蚈 O(n)。 + reverse() + は各階局のサむズ k に察しお O(k) ですが、 + すべおの階局のサむズの合蚈はちょうど n になるため、党䜓でも O(n) + に収たりたす。 空間に぀いおは、deque + に同時に入るノヌドは「最も幅の広い階局」だけなので最倧 O(n/2) = O(n) です。 +

+
+
+ + +
+

+ 📖 甚語集 +

+

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

+
+
+ + ▶ BFS幅優先探玢 + +
+ 朚やグラフを「階局ごず・暪方向に」順番に蚪問する探玢手法。キュヌ埅ち行列を䜿っお実装する。
+ 䟋え話マンションの1階を党宀確認しおから2階ぞ、2階を党宀確認しおから3階ぞ  ず進むむメヌゞ。深さ優先DFSずは逆のアプロヌチ。 +
+
+ +
+ + ▶ deque䞡端キュヌ + +
+ Python の + collections.deque + が提䟛するデヌタ構造。先頭・末尟ぞの远加・取り出しがどちらも + O(1)䞀定時間で行える。
+ 通垞の + list で + pop(0)先頭取り出しをするず O(n) かかるため、BFS キュヌには必ず deque + を䜿う。 +
+
+ +
+ + ▶ + ガヌド節早期リタヌン + +
+ 関数の先頭で特殊ケヌス空の入力・䞍正な倀などをチェックし、その堎で + return + する曞き方。
+ 埌続の凊理をネストさせずに枈み、コヌドをシンプルに保おる。この問題では + if root is None: return [] + がそれにあたる。 +
+
+ +
+ + ▶ in-place 操䜜 + +
+ 新しいメモリを確保せず、元のデヌタを盎接曞き換える操䜜。list.reverse() + がその代衚䟋。
+ 察比list[::-1] + は新しいリストを生成するPure 操䜜。in-place + の方が远加メモリを消費しない分、効率的。 +
+
+ +
+ + ▶ 䞍倉条件 + +
+ アルゎリズムが正しく動くために、凊理䞭ずっず成り立ち続けるべき条件のこず。
+ この問題では「while ルヌプの先頭で queue + に珟圚の階局のノヌドだけが栌玍されおいる」こずが䞍倉条件。level_size + の固定がこれを保蚌する。 +
+
+ +
+ + ▶ 完党二分朚 + +
+ 党おの葉子を持たないノヌドが同じ深さにある最もバランスの取れた二分朚。最䞋局の幅ノヌド数は党ノヌド数 + n の玄半分n/2になる。
+ この問題の空間蚈算量 O(n) を考えるずきに参考になる最悪ケヌス。 +
+
+ +
+ + ▶ キュヌQueue + +
+ 「先に入れたものを先に取り出す」デヌタ構造FIFO: First In First + Out。
+ 䟋え話コンビニのレゞの行列ず同じ。先に䞊んだ人が先に凊理される。BFS + では「次に蚪問すべきノヌド」をキュヌで管理する。 +
+
+ +
+ + ▶ ルヌトノヌド + +
+ 朚の最䞊䜍にある起点ノヌド頂点。朚党䜓の出発点で、芪を持たない唯䞀のノヌド。
+ BFS ではルヌトノヌドをキュヌに入れるこずで探玢を開始する。 +
+
+
+
+ + +
+ LeetCode 103 · Binary Tree Zigzag Level Order Traversal · BFS + 偶奇反転 +
+
+ + + + + + + + + diff --git a/public/index.html b/public/index.html index 55b6be0..0881b39 100644 --- a/public/index.html +++ b/public/index.html @@ -416,7 +416,7 @@

🧪 Algorithm Study Index

-

169 interactive lessons across 6 domains

+

170 interactive lessons across 6 domains

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

- + @@ -468,6 +468,7 @@

  • 🧩LeetCode #83 - Remove Duplicates from Sorted ListAlgorithm/Other/leetcode/83. Remove Duplicates from Sorted List/Claude 4.6 extended/README_React.html
  • 🧩LeetCode 100 — Same Tree | 再垰DFS解説Algorithm/Other/leetcode/100. Same Tree/claude sonnet 4.6 extended/README_react.html
  • 🧩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 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
  • @@ -644,6 +645,7 @@

  • 🧩LeetCode #83 - Remove Duplicates from Sorted ListAlgorithm/Other/leetcode/83. Remove Duplicates from Sorted List/Claude 4.6 extended/README_React.html
  • 🧩LeetCode 100 — Same Tree | 再垰DFS解説Algorithm/Other/leetcode/100. Same Tree/claude sonnet 4.6 extended/README_react.html
  • 🧩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 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
  • @@ -821,7 +823,7 @@

    🧪 - Generated on 2026-04-11 + Generated on 2026-04-12