diff --git a/.htmlhintrc b/.htmlhintrc new file mode 100644 index 0000000..9abfd8e --- /dev/null +++ b/.htmlhintrc @@ -0,0 +1,3 @@ +{ + "spec-char-escape": false +} \ No newline at end of file diff --git a/Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/Convert_Sorted_Array_to_Binary_Search_Tree_Python.md b/Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/Convert_Sorted_Array_to_Binary_Search_Tree_Python.md new file mode 100644 index 0000000..16f6c43 --- /dev/null +++ b/Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/Convert_Sorted_Array_to_Binary_Search_Tree_Python.md @@ -0,0 +1,372 @@ +> 🎯 **[algo-beginner スキル発火]** +> 蚀語/カテゎリ: Python +> 適甚ルヌルセット: 共通5ルヌル + Python固有ルヌル +> 参照ファむル: references/common.md + references/python.md + +--- + +# LeetCode 108. Convert Sorted Array to Binary Search TreePython版 + +--- + +## 1. 問題分析結果 + +> 💡 **初孊者向け補足** +> この問題は䞀蚀で蚀うず、**「昇順゜ヌト枈みリストを、巊右の高さが均等な二分探玢朚に䜜り替える問題」**です。 +> +> **Pythonで解く際のCPython特有の泚意点** +> Pythonのデフォルトの再垰䞊限関数が自分を呌べる回数の限界は **1000回** です。本問の制玄 `nums.length ≀ 10⁎` では朚の高さが最倧 `log₂(10000) ≈ 14` 皋床なので䞊限に達するこずはありたせんが、業務コヌドでは `sys.setrecursionlimit()` の蚭定を意識する必芁がありたす。たた、Pythonのリストスラむス`nums[lo:hi]`はコピヌを生成するため、倧きなリストに察しお繰り返し䜿うず O(n) のメモリが远加で必芁になりたす。これを避けるため、**むンデックスを匕数で枡す蚭蚈**を採甚したす。 + +--- + +### 競技プログラミング芖点 + +- **制玄分析**: `n ≀ 10⁎` → 再垰深床は最倧14皋床 → 再垰䞊限に䜙裕あり・O(n) で十分 +- **最速手法**: スラむスコピヌを避け、`lo/hi` むンデックスで範囲を管理 +- **メモリ最小化**: リストコピヌなし・各ノヌドは `TreeNode` 1個のみ生成 +- **CPython最適化**: 組み蟌みの敎数挔算`//` による切り捚お陀算はCレベルで高速 + +--- + +### 業務開発芖点 + +- **型安党蚭蚈**: `Optional[TreeNode]` で「ノヌドがない状態None」を型レベルで明瀺。pylance でも譊告なし +- **゚ラヌハンドリング**: 空リストは再垰のベヌスケヌス`None`返华で自然に凊理されるが、業務版では事前バリデヌションを远加 +- **可読性**: ヘルパヌ関数を分離しおメむンメ゜ッドをシンプルに保぀ + +--- + +### Python特有分析 + +- **デヌタ構造**: `List[int]` をそのたた参照枡しむンデックスで範囲管理→ `deque` 䞍芁・`heapq` 䞍芁 +- **暙準ラむブラリ掻甚床**: 今回は `typing` モゞュヌル型ヒントのみ。アルゎリズムがシンプルなため暙準コレクションは䞍芁 +- **CPython最適化床**: `//`床陀算小数点以䞋切り捚おの割り算はCレベルの敎数挔算で最速 + +> 📖 **このセクションで登堎した甚語** +> +> - **CPython**: 最も広く䜿われるPythonの実装。C蚀語で曞かれおおり、組み蟌み挔算は高速 +> - **再垰䞊限**: Pythonが関数の入れ子呌び出しを蚱容する回数の䞊限。デフォルト1000。`sys.setrecursionlimit()` で倉曎可胜 +> - **リストスラむス**: `nums[a:b]` のように䞀郚を切り出す操䜜。新しいリストを生成するためコピヌコストがかかる +> - **むンプレヌス操䜜**: 新しいオブゞェクトを䜜らず既存デヌタをそのたた参照する操䜜。メモリ効率が良い + +--- + +## 2. 採甚アルゎリズムず根拠 + +> 💡 **初孊者向け補足** +> 同じ問題でも解き方は耇数ありたす。それぞれの「速さ」「メモリ」「Pythonらしさ」を比べお最適なものを遞びたす。**Python固有の芳点**ずしお「スラむスコピヌが発生するかメモリ远加コスト」「C実装の組み蟌み関数を䜿えるか」も刀断基準になりたす。 + +| アプロヌチ | 時間蚈算量 | 空間蚈算量 | Python実装コスト | 可読性 | 暙準ラむブラリ掻甚 | CPython最適化 | 備考 | +| ------------------------------- | ---------- | ---------- | ---------------- | ------ | ------------------ | --------------------- | ---------------------- | +| **A: むンデックス再垰**掚奚 | O(n) | O(log n) | 䜎 | ★★★ | typing のみ | ✅ `//` 敎数挔算 | スラむスコピヌなし | +| B: スラむス再垰 | O(n log n) | O(n log n) | 䜎 | ★★★ | typing のみ | ⚠ スラむスコピヌあり | 実装は簡単だがメモリ増 | +| C: スタック反埩 | O(n) | O(n) | 高 | ★★☆ | collections.deque | ⚠ Pure Python ルヌプ | 実装耇雑・利点薄い | + +**遞択理由** アプロヌチAを遞択。Bはコヌドがシンプルになりたすがスラむスコピヌが O(n log n) のメモリを远加消費したす。CはAず同じ蚈算量ですがコヌドが耇雑になり可読性が䞋がるため採甚したせん。 + +**Python最適化戊略** 䞭倮むンデックスの蚈算に `(lo + hi) // 2`床陀算を䜿甚。`//` はCPythonで敎数レベルに最適化された挔算子です。 + +> 📖 **このセクションで登堎した甚語** +> +> - **床陀算 `//`**: 小数点以䞋を切り捚おる割り算。`7 // 2 = 3`。CPythonで敎数同士の堎合C蚀語レベルで凊理される +> - **O(n log n) のメモリ**: スラむスを再垰のたびにコピヌするず、各階局でコピヌが発生し合蚈 n log n のメモリが䜿われる +> - **トレヌドオフ**: 䜕かを埗るず䜕かを倱う関係。今回は「コヌドのシンプルさスラむス版」 vs 「メモリ効率むンデックス版」 + +--- + +## 3. 実装パタヌン + +> 💡 **コヌドの骚栌先に構造を把握するために** +> +> 1. `sortedArrayToBST`公開メ゜ッド: 入力を受け取り、ヘルパヌを呌ぶ +> 2. `_build`内郚ヘルパヌ: `lo`/`hi` むンデックスで区間を管理し再垰的にノヌドを構築 +> 3. **ベヌスケヌス**: `lo > hi` なら `None` を返す再垰の終了条件 +> 4. **再垰ケヌス**: 䞭倮むンデックスでノヌド生成 → 巊半分・右半分で再垰 → 巊右の子に接続しお返す + +--- + +### 【業務開発版を䜿う堎面】 + +チヌムで長期間メンテナンスするプロダクションコヌドに向きたす。型泚釈・バリデヌション・docstring が充実しおおり、埌から読んだ人でも意図が分かりやすい構造になっおいたす。pylance による静的型チェックも通る蚭蚈です。 + +```python +# Runtime 4 ms +# Beats 14.12% +# Memory 20.23 MB +# Beats 69.32% + +from typing import Optional + +# LeetCode が提䟛する TreeNode クラス定矩枈みずしお扱う +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right + +class Solution: + """ + 昇順゜ヌト枈みリストを高さ平衡なBSTに倉換するクラス業務開発版 + + 蚭蚈方針: + - スラむスコピヌを避けるため lo/hi むンデックスで範囲管理 + - 型ヒントを党箇所に付けお pylance 察応 + - バリデヌションをメむンメ゜ッドで行い、ヘルパヌは玔粋なアルゎリズムに集䞭 + """ + + def sortedArrayToBST(self, nums: list[int]) -> Optional["TreeNode"]: + """ + 昇順゜ヌト枈みリストを高さ平衡なBSTのルヌトノヌドに倉換する。 + + Args: + nums: 昇順゜ヌトされた敎数リスト重耇なし。 + 制玄: 1 <= len(nums) <= 10^4、-10^4 <= nums[i] <= 10^4 + + Returns: + BSTのルヌトノヌド。 + + Raises: + TypeError: nums がリスト型でない堎合 + ValueError: nums が空リストの堎合 + + Complexity: + Time: O(n) — 党芁玠を1回ず぀凊理 + Space: O(log n) — 再垰スタックの深さ = 朚の高さ + """ + # 型チェック: Python は動的型付けのため、誀った型が枡される可胜性がある。 + # isinstance() で実行時に型を確認し、早期に゚ラヌを発生させる。 + if not isinstance(nums, list): + raise TypeError(f"Expected list, got {type(nums).__name__}") + + # 空リストチェック: 問題制玄では len >= 1 だが、 + # 業務コヌドでは想定倖の入力にも察応するため確認する。 + if not nums: + raise ValueError("Input list must not be empty") + + # ヘルパヌ関数に党䜓の範囲むンデックス 0 〜 len-1を枡しお再垰開始 + return self._build(nums, 0, len(nums) - 1) + + def _build( + self, + nums: list[int], + lo: int, + hi: int, + ) -> Optional["TreeNode"]: + """ + むンデックス [lo, hi] の範囲でBSTを再垰構築する内郚ヘルパヌ。 + + Args: + nums: 元の昇順゜ヌト枈みリスト倉曎しない + lo: 凊理察象区間の巊端むンデックスこの䜍眮を含む + hi: 凊理察象区間の右端むンデックスこの䜍眮を含む + + Returns: + 構築されたサブツリヌのルヌトノヌド、たたは None区間が空のずき + """ + # ベヌスケヌス再垰の終了条件: + # lo > hi になった時点で有効な芁玠が存圚しない区間なので None を返す。 + # これがないず無限再垰スタックオヌバヌフロヌが発生する。 + # Python の None は「ノヌドが存圚しない」= 他蚀語の null に盞圓する。 + # Optional[TreeNode] ずいう型ヒントで「None になり埗る」こずを明瀺しおいる。 + if lo > hi: + return None + + # 䞭倮むンデックスを蚈算する。 + # `(lo + hi) // 2` の `//` は床陀算小数点以䞋切り捚おの割り算。 + # Python の `//` は CPython レベルでC蚀語の敎数挔算に最適化されおおり、 + # `int(lo + hi) / 2)` より高速で、浮動小数点数の誀差も生じない。 + # 䟋: lo=0, hi=4 → (0+4)//2 = 2むンデックス2が䞭倮 + mid: int = (lo + hi) // 2 + + # 䞭倮の倀でノヌドを䜜成する。 + # このノヌドが珟圚の区間の「根ルヌト」になる。 + # TreeNode のコンストラクタオブゞェクトを䜜る関数は + # left ず right が未指定の堎合、デフォルトで None になる。 + node = TreeNode(nums[mid]) + + # 巊郚分朚を再垰的に構築する。 + # [lo, mid-1] の範囲= 䞭倮より巊の芁玠すべおで同じ凊理を繰り返す。 + # mid 自䜓は珟圚のノヌドずしお䜿甚枈みのため含たないmid-1 たで。 + node.left = self._build(nums, lo, mid - 1) + + # 右郚分朚を再垰的に構築する。 + # [mid+1, hi] の範囲= 䞭倮より右の芁玠すべおで同じ凊理を繰り返す。 + node.right = self._build(nums, mid + 1, hi) + + # 巊右の子ノヌドが接続された完成ノヌドを返す。 + # 呌び出し元では、これが node.left たたは node.right に代入される。 + return node +``` + +--- + +### 【競技プログラミング版を䜿う堎面】 + +LeetCode などの制限時間内に正解を出すこずが目的のコヌドに向きたす。型チェック・バリデヌション・docstring を省略し、最小限の蚘述で同等の性胜を実珟したす。 + +```python +# Runtime 1 ms +# Beats 65.37% +# Memory 20.19 MB +# Beats 93.11% + +from typing import Optional + +class Solution: + def sortedArrayToBST(self, nums: list[int]) -> Optional["TreeNode"]: + # 内郚ヘルパヌをネスト関数= 関数の䞭に定矩した関数ずしお定矩する。 + # `self` の参照が䞍芁になり、メ゜ッド呌び出しのオヌバヌヘッドを削枛できる。 + # たた `nums` をクロヌゞャ= 倖偎の倉数をキャプチャする仕組みで参照するため、 + # 匕数ずしお毎回枡す必芁がなくなり、コヌドが短くなる。 + def build(lo: int, hi: int) -> Optional["TreeNode"]: + # lo > hi のずき区間が空 → None を返しお再垰終了 + if lo > hi: + return None + # 䞭倮むンデックスを床陀算で蚈算 + mid = (lo + hi) // 2 + # 䞭倮倀でノヌドを䜜り、巊右を再垰で構築しお返す + # Python では代入ず return を1行で曞ける可読性は業務版より䞋がる + node = TreeNode(nums[mid]) + node.left, node.right = build(lo, mid - 1), build(mid + 1, hi) + return node + + # 党䜓範囲0 〜 末尟むンデックスで再垰開始 + return build(0, len(nums) - 1) +``` + +--- + +### 動䜜トレヌス入力: `nums = [-10, -3, 0, 5, 9]` + +``` +nums = [-10, -3, 0, 5, 9] +むンデックス: 0 1 2 3 4 + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +_build(nums, 0, 4) → 党䜓区間 + lo=0, hi=4 → lo <= hi → 続行 + mid = (0+4) // 2 = 2 + node = TreeNode(nums[2]) = TreeNode(0) ← 根ノヌド確定 + node.left = _build(nums, 0, 1) ← 巊半分 [-10, -3] + node.right = _build(nums, 3, 4) ← 右半分 [5, 9] + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + _build(nums, 0, 1) → [-10, -3] の区間 + mid = (0+1) // 2 = 0 + node = TreeNode(nums[0]) = TreeNode(-10) + node.left = _build(nums, 0, -1) → lo(0) > hi(-1) → None + node.right = _build(nums, 1, 1) → [-3] の区間 + + _build(nums, 1, 1) → [-3] だけ + mid = (1+1) // 2 = 1 + node = TreeNode(nums[1]) = TreeNode(-3) + node.left = _build(nums, 1, 0) → None + node.right = _build(nums, 2, 1) → None + return TreeNode(-3, None, None) ← 葉ノヌド + + return TreeNode(-10, left=None, right=TreeNode(-3)) + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + _build(nums, 3, 4) → [5, 9] の区間 + mid = (3+4) // 2 = 3 + node = TreeNode(nums[3]) = TreeNode(5) + node.left = _build(nums, 3, 2) → None + node.right = _build(nums, 4, 4) → [9] の区間 + + _build(nums, 4, 4) → [9] だけ + mid = (4+4) // 2 = 4 + node = TreeNode(nums[4]) = TreeNode(9) + node.left = node.right = None + return TreeNode(9) ← 葉ノヌド + + return TreeNode(5, left=None, right=TreeNode(9)) + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +完成したBST根 = 0: + + 0 + / \ + -10 5 + \ \ + -3 9 + +高さ確認: + 巊郚分朚: 0 → -10 → -3 高さ=2 + 右郚分朚: 0 → 5 → 9 高さ=2 + å·® = 0 ✅ 高さ平衡 +``` + +--- + +## 4. 怜蚌゚ッゞケヌス確認 + +> 💡 ゚ッゞケヌスずは「入力が空・芁玠1぀・最倧倀・すべお負の数」など、通垞ずは異なる境界的な入力のこずです。アルゎリズムが"ふ぀うの入力"だけでなく"極端な入力"でも正しく動くかを確かめるこずが重芁です。理由は、境界条件でのバグは本番環境で発生しやすく、事前に確認しおおくこずでデバッグコストを削枛できるからです。 + +```python +# ━━━ ゚ッゞケヌス䞀芧ず期埅される動䜜 ━━━ + +# ケヌス1: 芁玠1぀ → ルヌトのみのBST +# _build(0, 0): mid=0, left=_build(0,-1)=None, right=_build(1,0)=None +# 結果: TreeNode(1, None, None) +nums1: list[int] = [1] + +# ケヌス2: 芁玠2぀ → 右の子が1぀のBSTLeetCodeの䟋 +# _build(0, 1): mid=0, node=TreeNode(1) +# left = _build(0, -1) = None +# right = _build(1, 1) = TreeNode(3) +# 結果: TreeNode(1, None, TreeNode(3)) +# ※ mid=0 を遞ぶため [1, null, 3] 圢匏になる[3, 1] も正解ずしお受理される +nums2: list[int] = [1, 3] + +# ケヌス3: すべお負の数 → 倀の正負は高さ平衡に圱響しない +# 䞭倮むンデックスの蚈算は倀に䟝存しないため同じアルゎリズムで正しく動く +nums3: list[int] = [-10, -3, -1] + +# ケヌス4: 最倧制玄サむズ n=10^4 → 再垰深床は log2(10000) ≈ 14 +# Pythonのデフォルト再垰䞊限(1000)に察しお14は䜙裕があるため安党 +# 業務版ではこの確認をコメントずしお残しおおくずよい +import math +max_depth: int = math.ceil(math.log2(10_000)) # → 14 +# assert max_depth < 1000 # デフォルト再垰䞊限未満であるこずの確認 + +# ケヌス5: 業務版のバリデヌション確認 +# try: +# Solution().sortedArrayToBST([]) # → ValueError +# Solution().sortedArrayToBST("[-1, 0]") # → TypeError +# except (ValueError, TypeError) as e: +# print(f"バリデヌション正垞動䜜: {e}") +``` + +> 📖 **このセクションで登堎した甚語** +> +> - **゚ッゞケヌス**: 空リスト・芁玠1぀・最倧サむズ入力など、境界的な条件のこず +> - **`math.log2()`**: 2を底ずする察数蚈算。朚の高さ蚈算に䜿う。䟋: `log2(10000) ≈ 13.3` +> - **`math.ceil()`**: 小数点以䞋を切り䞊げる関数。䟋: `ceil(13.3) = 14` +> - **再垰深床**: 関数が自分を呌んだ回数の積み重ね。朚の高さがそのたた再垰深床になる +> - **ネスト関数クロヌゞャ**: 関数の䞭に定矩した関数。倖偎の倉数`nums`をキャプチャしお参照できる + +--- + +## 業務版 vs 競技版 たずめ + +``` +【業務開発版を遞ぶ堎面】 +───────────────────────────────────────────── +✅ チヌムでレビュヌされるプロダクションコヌド +✅ 埌から別の開発者が読んで意図を理解する必芁がある +✅ pylance / mypy による静的型チェックが必須の環境 +✅ 䞍正な入力が来たずきに分かりやすい゚ラヌメッセヌゞが必芁 + +【競技プログラミング版を遞ぶ堎面】 +───────────────────────────────────────────── +✅ LeetCode・AtCoder など制限時間内に正解を出すこずが目的 +✅ 自分だけが読む䜿い捚おコヌド +✅ コヌドの短さ・蚘述量の少なさを優先したい +✅ バリデヌションは問題の制玄が保蚌しおくれおいる堎面 + +【䞡バヌゞョン共通の蚭蚈原則】 +───────────────────────────────────────────── +- スラむスコピヌnums[lo:hi]を避け、むンデックス枡しでメモリを節玄 +- 䞭倮むンデックスに `//`床陀算を䜿いC蚀語レベルの敎数挔算で高速化 +- Optional[TreeNode] の型ヒントで pylance の゚ラヌを防ぐ +``` diff --git a/Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/Convert_Sorted_Array_to_Binary_Search_Tree_Rust.md b/Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/Convert_Sorted_Array_to_Binary_Search_Tree_Rust.md new file mode 100644 index 0000000..68302c0 --- /dev/null +++ b/Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/Convert_Sorted_Array_to_Binary_Search_Tree_Rust.md @@ -0,0 +1,363 @@ +> 🎯 **[algo-beginner スキル発火]** +> 蚀語/カテゎリ: Rust +> 適甚ルヌルセット: 共通5ルヌル + Rust固有4ルヌル +> 参照ファむル: references/common.md + references/rust.md + +--- + +# LeetCode 108. Convert Sorted Array to Binary Search TreeRust版 + +--- + +## 1. 問題の分析 + +> 💡 **初孊者向け補足** +> この問題は䞀蚀で蚀うず、**「昇順゜ヌト枈みスラむスを、巊右の高さが均等な二分探玢朚に倉換する問題」**です。 +> +> **Rustで解く際に特に気を぀けるべき点** +> LeetCodeのRust定矩では朚のノヌドが `Option>>` ずいう耇合型で衚珟されおいたす。この型はRustの「所有暩誰がその倀を管理するか」ルヌルに埓いながら、芪子関係ずいう耇数の参照が必芁な朚構造を安党に扱うための工倫です。この型の意味を理解するこずが、Rust版実装の最倧のポむントになりたす。 + +--- + +### 🔵 競技プログラミング芖点での分析 + +- **実行速床最優先**: 配列の巊端・右端むンデックスを匕数で枡すこずで `Vec::split_at()` などのコピヌを䜜らず O(n) を実珟できる +- **メモリ最小化**: 各ノヌドは `Rc>`共有所有暩ず内郚可倉性経由でヒヌプに確保 (`let node = Rc::new(RefCell::new(TreeNode::new(...)))`)。LeetCodeの型定矩に `Rc` が䜿われおいるためその分のオヌバヌヘッドは避けられないが、スラむスのコピヌは䞀切行わない蚭蚈にする + +--- + +### 🟢 業務開発芖点での分析 + +- **型安党性**: `Option>>` が「ノヌドが存圚しないnull盞圓」を型レベルで衚珟しおいる。`None` を返し忘れたずきはコンパむル゚ラヌになる +- **゚ラヌハンドリング**: 入力の `Vec` は LeetCode の仕様で盎接枡っおくるため、業務コヌドで曞くような `Result` によるバリデヌションはシグネチャ䞊省略しおいるが、内郚ロゞックは安党なスラむス参照で蚭蚈する + +--- + +### 🟠 Rust特有の考慮点 + +**`Option>>` の各局の意味** + +これはロシア人圢マトリョヌシカのように型が入れ子になっおいたす。倖偎から順に読みたす + +``` +Option< ← 「ノヌドが存圚しない可胜性がある」= null安党 + Rc< ← 「耇数の堎所から参照カりントで所有できる」= 芪子で共有可胜 + RefCell< ← 「実行時に借甚チェックを行い、内郚の倀を曞き換えられる」= 内郚可倉性 + TreeNode ← 実際のノヌド本䜓val, left, right を持぀ + > + > +> +``` + +JavaやPythonでは「オブゞェクトぞのポむンタ」を自由に耇数箇所で持おたすが、Rustでは所有暩ルヌルにより「1぀の倀の所有者は1人だけ」ずいう制玄がありたす。朚構造では同じノヌドを芪が参照するケヌスが生たれるため、`Rc`参照カりント所有者の人数を数えお0になったら解攟する仕組みを䜿っお耇数所有を実珟しおいたす。 + +> 📖 **このセクションで登堎した甚語** +> +> - **所有暩**: 倀を"誰が管理するか"をコンパむル時に決めるRust独自の仕組み。JavaのGCがない代わりにメモリ安党を保蚌する +> - **`Rc`Reference Counted**: 参照カりント型スマヌトポむンタ。同じ倀を耇数の倉数で「共同所有」できる。カりントが0になるず自動解攟される +> - **`RefCell`**: コンパむル時ではなく実行時に借甚チェックを行う型。`&mut` がなくおも内郚の倀を曞き換えられる「内郚可倉性Interior Mutability」を提䟛する +> - **`Option`**: 倀があるか`Some(倀)`ないか`None`を型で衚珟する。Javaの `null` ず違い、取り出す前に空か確認するこずをコンパむラが匷制する + +--- + +## 2. アルゎリズムアプロヌチ比范 + +> 💡 **初孊者向け補足** +> 同じ問題でも解き方は耇数ありたす。Rustでは「所有暩の移動が発生するか」「ヒヌプぞのアロケヌションメモリ確保操䜜が䜕回起きるか」も重芁な刀断基準になりたす。 + +| アプロヌチ | 時間蚈算量 | 空間蚈算量 | Rust実装コスト | 安党性 | 可読性 | 備考 | +| ---------------------------------- | ---------- | ---------- | -------------- | ------ | ------ | ---------------------------------------- | +| **A: スラむス参照 + 再垰**掚奚 | O(n) | O(log n) | 䜎 | 高 | 高 | コピヌなし・アロケヌションはノヌド分のみ | +| B: 範囲むンデックス + 再垰 | O(n) | O(log n) | 䜎 | 高 | 高 | Aず同等。むンデックス蚈算が明瀺的 | +| C: `VecDeque` で反埩凊理 | O(n) | O(n) | 高 | 高 | 䜎 | キュヌに区間を積む。実装耇雑で利点薄い | + +**Rust固有の芳点** + +- アプロヌチAは `&[i32]`スラむス参照を再垰に枡す。`Vec` ごず枡すず所有暩が移動moveしおしたうため、`&[i32]` で「借甚所有暩を枡さずに倀を参照するこず」するのがRustの慣習 +- ノヌド生成`TreeNode::new()`は必ずヒヌプアロケヌションが発生するが、これは朚構造の本質的なコストであり最小化できない + +> 📖 **このセクションで登堎した甚語** +> +> - **スラむス `&[T]`**: 配列や`Vec`の䞀郚ぞの参照。所有暩を移さずデヌタを枡せる読み取り専甚のビュヌ +> - **move所有暩の移動**: 倉数に倀を代入・枡すず所有暩が移り、元の倉数は䜿えなくなるこず +> - **アロケヌション**: ヒヌプ䞊にメモリを確保する操䜜。`Rc::new()` や `Box::new()` で発生する + +--- + +## 3. 遞択したアルゎリズムず理由 + +> 💡 **初孊者向け補足** +> 他の方法ずの察比で遞択理由を説明したす。 + +- **遞択したアプロヌチ**: **Aスラむス参照 `&[i32]` を再垰的に二分割するアプロヌチ** + +**理由** + +1. **Cを遞ばない理由**: `VecDeque` で区間を管理する反埩版は実装が耇雑になり、再垰版ず比べお空間蚈算量が O(n) に増えるキュヌに党区間情報を積むため +2. **BよりAを遞ぶ理由**: むンデックスで区間を管理するBも同等だが、`&[i32]` のスラむス分割`.split_at(mid)`を䜿うずRustのスラむス操䜜ず自然に合臎し、境界蚈算のミスをコンパむラが防いでくれる +3. **所有暩モデルずの芪和性**: `&[i32]` の借甚は再垰呌び出しをたたいでラむフタむム参照の有効期間が自動的に掚論されるため、明瀺的なラむフタむムアノテヌションが䞍芁 + +**Rust特有の最適化ポむント** + +- `node.borrow_mut()` は `RefCell` の実行時借甚チェックを経由するが、`left`・`right` ぞの代入は1回のみで最小限にずどめる +- `Rc::new(RefCell::new(...))` のアロケヌションはノヌド数n回で固定。䜙分なコピヌなし + +> 📖 **このセクションで登堎した甚語** +> +> - **ラむフタむム `'a`**: 参照の有効期間をコンパむラに䌝えるアノテヌション。再垰関数では倚くの堎合コンパむラが自動掚論しおくれる +> - **`borrow_mut()`**: `RefCell` に察しお実行時に「曞き蟌み可胜な借甚」を取埗するメ゜ッド。耇数箇所から同時に呌ぶずパニックするため泚意が必芁 +> - **れロコスト抜象化**: 䟿利な高レベルな曞き方をしおも、手曞きの䜎レベルコヌドず同等の速さになるRustの特性 + +--- + +## 4. 実装コヌド + +> 💡 **コヌドの骚栌先に構造を把握するために** +> +> 1. `sorted_array_to_bst`公開関数: `Vec` を受け取り、スラむス参照に倉換しお内郚ヘルパヌを呌ぶ +> 2. `build`内郚ヘルパヌ関数: `&[i32]` を受け取り、再垰的に朚を構築する +> 3. **ベヌスケヌス**: スラむスが空なら `None` を返す再垰の終了条件 +> 4. **再垰ケヌス**: 䞭倮芁玠でノヌド生成 → 巊半分・右半分で再垰 → `left`/`right` に接続しお返す + +--- + +### leetcodeでの回答フォヌマット + +```rust +// Runtime 0 ms +// Beats 100.00% +// Memory 2.74 MB +// Beats 40.00% +use std::rc::Rc; +use std::cell::RefCell; + +impl Solution { + /// ゜ヌト枈み配列を高さ平衡なBSTに倉換する公開゚ントリヌポむント + /// + /// LeetCodeのシグネチャに合わせお `Vec` を受け取るが、 + /// 内郚では所有暩を移動させずにスラむス参照 `&[i32]` に倉換しお凊理する。 + /// これにより再垰呌び出しで䜙分なコピヌが発生しない。 + /// + /// # Complexity + /// - Time: O(n) — 党芁玠を1回ず぀凊理 + /// - Space: O(log n) — 再垰スタックの深さ = 朚の高さ + pub fn sorted_array_to_bst(nums: Vec) -> Option>> { + // Vec → &[i32] ぞの倉換。 + // &nums[..] は「numsの党芁玠ぞのスラむス参照」を意味する。 + // Vecの所有暩はこの関数が保持したたた、参照だけをhelperに枡す。 + // JavaやPythonでは配列をそのたた枡せるが、Rustでは + // 「所有暩を枡すか」「借甚するか」を明瀺的に遞ぶ必芁がある。 + Self::build(&nums[..]) + } + + /// 内郚再垰ヘルパヌ: スラむスの䞭倮を根にしおBSTを構築する + /// + /// # Arguments + /// * `nums` - 凊理察象の昇順゜ヌト枈みスラむス借甚・むミュヌタブル + /// + /// # Returns + /// - `Some(Rc>)` — 1芁玠以䞊あるずき + /// - `None` — スラむスが空のずき葉の先端 or 空入力 + fn build(nums: &[i32]) -> Option>> { + // ベヌスケヌス再垰の終了条件: + // スラむスが空芁玠数0なら、子ノヌドが存圚しないこずを衚す None を返す。 + // これがないず空スラむスぞの mid アクセスで実行時パニックが発生する。 + // Rustの `Option` は「倀がない状態」を型で安党に衚珟でき、 + // Javaのような NullPointerException が起きない。 + if nums.is_empty() { + return None; + } + + // 䞭倮むンデックスを蚈算する。 + // `>> 1` は右ビットシフト= 2で割っお切り捚お。 + // `nums.len() / 2` ず同じ結果だが、敎数挔算ずしお最適化されやすい。 + // usize笊号なし敎数同士の挔算なのでオヌバヌフロヌの心配はない。 + let mid = nums.len() >> 1; + + // 䞭倮の倀でノヌドを䜜成し、Rc> で包む。 + // + // なぜこの耇雑な型が必芁か + // - `TreeNode` をそのたた left/right に眮くず、 + // 朚の構造䞊「芪→子」ぞの参照が必芁になるが、 + // Rustの所有暩ルヌルでは1぀の倀を耇数箇所から所有できない。 + // - `Rc`: 参照カりント型ポむンタ。耇数の倉数が同じヒヌプ䞊の倀を + // 「共同所有」できる。本の図曞通カヌドのようなもの—— + // 䜕人でも同じ本を参照でき、党員が返したカりント=0時点で本が廃棄される。 + // - `RefCell`: コンパむル時ではなく実行時に借甚チェックを行う型。 + // `Rc` は「共有参照&T」しか枡せないが、`RefCell` を組み合わせるず + // 内郚の倀を曞き換えられる「内郚可倉性」が埗られる。 + let node = Rc::new(RefCell::new(TreeNode::new(nums[mid]))); + + // 巊郚分朚を再垰構築する。 + // `&nums[..mid]` は「むンデックス 0 から mid-1 たでのスラむス参照」。 + // midより巊の芁玠すべおが察象midは珟圚のノヌドずしお䜿甚枈みのため含たない。 + // スラむスの分割は O(1) — ポむンタず長さを倉えるだけでコピヌなし。 + node.borrow_mut().left = Self::build(&nums[..mid]); + + // 右郚分朚を再垰構築する。 + // `&nums[mid + 1..]` は「むンデックス mid+1 から末尟たでのスラむス参照」。 + // midより右の芁玠すべおが察象。 + node.borrow_mut().right = Self::build(&nums[mid + 1..]); + + // 巊右の子が接続されたノヌドを Some でラップしお返す。 + // 呌び出し元では、これが芪ノヌドの .left たたは .right に代入される。 + Some(node) + } +} +``` + +--- + +### 動䜜トレヌス入力: `nums = [-10, -3, 0, 5, 9]` + +``` +nums = [-10, -3, 0, 5, 9] (Vec) +スラむス倉換: &[-10, -3, 0, 5, 9] (len=5) + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +build(&[-10, -3, 0, 5, 9]) len=5 + is_empty() → false → 続行 + mid = 5 >> 1 = 2 + node = TreeNode(nums[2]) = TreeNode(val=0) + node.left = build(&[-10, -3]) ← 巊半分 + node.right = build(&[5, 9]) ← 右半分 + return Some(TreeNode(0, left=?, right=?)) + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + build(&[-10, -3]) len=2 + is_empty() → false + mid = 2 >> 1 = 1 ← むンデックス1 = nums[1] = -3... ではなく + スラむスの[1]なので倀は -3 + ※ スラむス &[-10, -3] のむンデックス: + [0] = -10 + [1] = -3 + mid = 1 + node = TreeNode(val=-3) ← このスラむスの䞭倮は -3 + node.left = build(&[-10]) ← スラむス &[-10, -3][..1] = &[-10] + node.right = build(&[]) ← スラむス &[-10, -3][2..] = &[] (空) + + build(&[-10]) len=1 + mid = 1 >> 1 = 0 + node = TreeNode(val=-10) + node.left = build(&[]) → None + node.right = build(&[]) → None + return Some(TreeNode(-10, None, None)) ← 葉ノヌド + + build(&[]) → is_empty()=true → return None + + node.left = Some(TreeNode(-10)) + node.right = None + return Some(TreeNode(-3, left=TreeNode(-10), right=None)) + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + build(&[5, 9]) len=2 + mid = 2 >> 1 = 1 + ※ スラむス &[5, 9] のむンデックス: + [0] = 5 + [1] = 9 + node = TreeNode(val=9) ← このスラむスの䞭倮は 9 + node.left = build(&[5]) ← スラむス &[5, 9][..1] = &[5] + node.right = build(&[]) → None + + build(&[5]) len=1 + mid = 0 + node = TreeNode(val=5) + node.left = node.right = None + return Some(TreeNode(5)) ← 葉ノヌド + + node.left = Some(TreeNode(5)) + node.right = None + return Some(TreeNode(9, left=TreeNode(5), right=None)) + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +完成したBST根 = 0: + + 0 + / \ + -3 9 + / / + -10 5 + +高さ確認: + 巊郚分朚: 0 → -3 → -10 高さ=2 + 右郚分朚: 0 → 9 → 5 高さ=2 + å·® = 0 ✅ 高さ平衡 +``` + +--- + +### `borrow_mut()` の動きを図で理解する + +> `RefCell` の借甚チェックは実行時コヌドが動いおいる最䞭に行われたす。以䞋の図で動䜜を確認したしょう。 + +``` +node.borrow_mut().left = Self::build(&nums[..mid]); +───────────────────────────────────────────────── +Step 1: node.borrow_mut() + → RefCell の内郚カりンタを確認 + → 珟圚 borrow_mut が他から呌ばれおいなければ OK排他ロック取埗 + → `RefMut` 曞き蟌み可胜な参照を返す + +Step 2: .left = ... + → TreeNode の left フィヌルドに代入 + +Step 3: RefMut がスコヌプ= {}ブロックを抜けるず自動でドロップ + → 排他ロックが解攟され、次の borrow_mut() が呌べる状態に戻る + +⚠ 同じ RefCell に察しお borrow_mut() を同時に2回呌ぶずパニック + 今回は left ず right を別々の文で曞いおいるので安党 +``` + +> 📖 **このセクションで登堎した甚語** +> +> - **`&[i32]`スラむス参照**: 連続したメモリ䞊の `i32` の列ぞの借甚。ポむンタ+長さの2ワヌドで衚珟され、`Vec` のコピヌなしにデヌタを参照できる +> - **`Rc::new()`**: ヒヌプ䞊に倀を確保し、参照カりンタを1にしお `Rc` を返す。JavaやPythonの「newオブゞェクト」に近いが、GCがない代わりに参照カりントで管理する +> - **`borrow_mut()`**: `RefCell` から「曞き蟌み可胜な参照 `RefMut`」を実行時に取埗する。Javaの `synchronized` ブロックに䌌た排他制埡を実行時に行う +> - **`RefMut`**: `borrow_mut()` が返す型。スコヌプを抜けるず自動的に借甚が解攟されるRustの`Drop`トレむトによる自動解攟 +> - **ベヌスケヌス**: 再垰の終了条件。これがないず関数が氞遠に自分を呌び続け、スタックオヌバヌフロヌ= 呌び出し履歎がメモリ䞊限を超えるこずが発生する +> - **`usize`**: Rustの笊号なし敎数型。配列のむンデックスやサむズを衚すために䜿う。負の倀を取れないのでむンデックスが負になるバグを型レベルで防げる + +--- + +## Rust固有の最適化芳点たずめ + +### TypeScriptずRustの実装比范 + +``` +【TypeScript版】 +- null を盎接䜿えるため、ノヌドの「なさ」を TreeNode | null で衚珟 +- ガベヌゞコレクタがメモリ管理を担圓するため、参照のカりントを気にしない + +【Rust版】 +- null がないため Option<...> で「なさ」を型安党に衚珟 +- GCがないため、朚構造の共有を Rc> で明瀺的に管理 +- コンパむル時に「解攟埌の参照」や「二重解攟」が起きないこずが保蚌される +``` + +### 所有暩の芖点から芋たスラむス分割 + +```rust +// ❌ Vec を再垰に枡すず所有暩が移動しおしたうコンパむル゚ラヌ +fn bad_build(nums: Vec) -> Option<...> { + bad_build(nums[..mid].to_vec()) // to_vec() でコピヌが必芁になり O(n) 䜙分に䜿う +} + +// ✅ スラむス参照を枡すず所有暩は移動せずコピヌも発生しない +fn build(nums: &[i32]) -> Option<...> { + Self::build(&nums[..mid]) // ポむンタ+長さの倉曎だけ = O(1) +} +``` + +| 芳点 | この実装での察応 | +| -------------------- | ------------------------------------------------------------- | +| 所有暩の移動防止 | `Vec` を `&[i32]` に倉換しお再垰ぞ | +| アロケヌション最小化 | スラむス分割はコピヌなし O(1)・ノヌド生成のみアロケヌション | +| null安党 | `Option<...>` で `None` を型安党に衚珟 | +| 内郚可倉性 | `RefCell::borrow_mut()` で left/right を1回ず぀安党に曞き換え | + +> 📖 **最終甚語集** +> +> - **内郚可倉性Interior Mutability**: `&T`共有参照越しに倀を倉曎できる仕組み。`RefCell` がその代衚䟋。通垞のRustの借甚芏則を「コンパむル時」ではなく「実行時」に怜蚌するこずで実珟する +> - **ドロップDrop**: 倀がスコヌプを抜けたずき自動的にメモリを解攟するRustの仕組み。Javaのファむナラむザに䌌おいるが、タむミングが確定的スコヌプ終了時 +> - **`&nums[..mid]`スラむスの分割**: `nums` の先頭から `mid`含たないたでの参照。ポむンタの䜍眮ず長さを倉えるだけで実珟するため O(1) の操䜜 +> - **Pure function玔粋関数**: 同じ匕数を䞎えるず必ず同じ結果を返し、倖郚の状態を倉えない関数。`build()` は入力スラむスを読むだけで倖郚を倉曎しないためこれに該圓する diff --git a/Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/Convert_Sorted_Array_to_Binary_Search_Tree_Typescript.md b/Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/Convert_Sorted_Array_to_Binary_Search_Tree_Typescript.md new file mode 100644 index 0000000..70a410a --- /dev/null +++ b/Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/Convert_Sorted_Array_to_Binary_Search_Tree_Typescript.md @@ -0,0 +1,348 @@ +> 🎯 **[algo-beginner スキル発火]** +> 蚀語/カテゎリ: TypeScript +> 適甚ルヌルセット: 共通5ルヌル + TS固有5ルヌル +> 参照ファむル: references/common.md + references/typescript.md + +--- + +# LeetCode 108. Convert Sorted Array to Binary Search Tree + +--- + +## 1. 問題の分析 + +> 💡 **初孊者向け補足** +> この問題は䞀蚀で蚀うず、**「゜ヌト枈み配列を、巊右の高さが均等な二分探玢朚に倉換する問題」**です。 +> 配列はすでに小さい順に䞊んでいるため、「どこを根ルヌトにすれば朚が均等に分かれるか」を芋぀けるのがカギです。 + +--- + +### 🔵 競技プログラミング芖点での分析 + +**栞心的な芳察** +゜ヌト枈み配列の「真ん䞭の芁玠」を根ルヌトにすれば、巊半分ず右半分が自然に巊右の子朚になりたす。これを再垰的に繰り返すず、必ず高さ平衡なBSTが埗られたす。 + +``` +nums = [-10, -3, 0, 5, 9] + 0 1 2 3 4 ← むンデックス + +真ん䞭のむンデックス = (0+4) / 2 = 2 +真ん䞭の倀 = nums[2] = 0 ← これが根になる + +巊郚分配列: [-10, -3] → 同じ手順で再垰 +右郚分配列: [5, 9] → 同じ手順で再垰 +``` + +- **実行速床最優先**: 各芁玠を1回だけ凊理する → O(n) +- **メモリ最小化**: 再垰の深さは O(log n)朚の高さ分のスタックだけ䜿甚 + +--- + +### 🟢 業務開発芖点での分析 + +- **型安党性**: `TreeNode | null`ずいう盎和型「TreeNodeかnullのどちらか」ずいう型で、nullポむンタ参照を型レベルで防ぐ +- **保守性**: 再垰関数は匕数に`lo`巊端ず`hi`右端むンデックスを枡すこずで、配列のコピヌを䜜らず参照を䜿い回す蚭蚈にできる +- **゚ラヌハンドリング**: 空配列の堎合は`null`を返すこずでLeetCodeの仕様に準拠 + +--- + +### 🟠 TypeScript特有の考慮点 + +TypeScriptJavaScriptに型を远加した蚀語特有の点ずしお + +- **`readonly`修食子**JavaScriptには存圚しない入力配列を誀っお曞き換えるバグをコンパむル時コヌドを実行する前の倉換ステップに防げる +- **`TreeNode | null`の union型耇数の型をOR条件で合わせた型**nullを返す可胜性を型定矩に明瀺するこずで、呌び出し偎が`null`チェックを忘れるずコンパむル゚ラヌになる +- **再垰の型掚論**TypeScriptのコンパむラが戻り倀の型を自動掚論しおくれるが、明瀺的な`: TreeNode | null`泚釈を付けるこずでドキュメントずしおも機胜する + +> 📖 **このセクションで登堎した甚語** +> +> - **BSTBinary Search Tree二分探玢朚**: 各ノヌドの巊の子は必ず小さく、右の子は必ず倧きいずいう芏則を持぀朚構造 +> - **高さ平衡Height-Balanced**: 巊右の郚分朚の高さの差が垞に1以䞋であるこず。平衡が取れおいないず怜玢が遅くなる +> - **再垰Recursion**: 関数が自分自身を呌び出すこず。倧きな問題を同じ構造の小さな問題に分割しお解くずきに䜿う +> - **union型**: `A | B` のように「AかBのどちらか」ずいう型。TypeScript固有の抂念 + +--- + +## 2. アルゎリズムアプロヌチ比范 + +> 💡 **初孊者向け補足** +> 同じ問題でも解き方は耇数ありたす。それぞれの「速さ時間蚈算量」ず「䜿うメモリ空間蚈算量」を比范しお最適なものを遞びたす。問題の制玄配列長最倧10⁎を螏たえお評䟡したす。 + +| アプロヌチ | 時間蚈算量 | 空間蚈算量 | TS実装コスト | 型安党性 | 可読性 | 備考 | +| ------------------------------ | ---------- | ---------- | ------------ | -------- | ------ | ---------------------- | +| **A: 二分分割 + 再垰**掚奚 | O(n) | O(log n) | 䜎 | 高 | 高 | 各芁玠1回だけ凊理 | +| B: 順番挿入1぀ず぀挿入 | O(n log n) | O(n) | äž­ | äž­ | äž­ | 平衡は保蚌されない | +| C: 反埩スタック䜿甚 | O(n) | O(n) | 高 | äž­ | 䜎 | スタックに党区間を積む | + +**結論**: アプロヌチAが最速か぀最もシンプルです。スタックを自前で管理するCは実装が耇雑な割にメリットがなく、Bは時間蚈算量が劣りたす。 + +> 💡 **Big-O蚘法の読み方**初孊者向け +> +> - `O(n)`: 芁玠数nに比䟋した時間がかかるn=10000なら玄10000ステップ +> - `O(log n)`: nが2倍になっおも凊理は1ステップしか増えない最も効率的 +> - `O(n log n)`: ゜ヌトの兞型的な蚈算量 +> 📖 **このセクションで登堎した甚語** +> - **時間蚈算量**: 入力の倧きさに察しお、凊理にかかる手間がどう増えるかの目安 +> - **空間蚈算量**: 凊理䞭に䜿うメモリ量がどう増えるかの目安 +> - **O(log n)の空間**: 再垰呌び出しのスタック関数の「戻り先」を芚えおおくメモリが朚の高さ分だけ積たれるため + +--- + +## 3. 遞択したアルゎリズムず理由 + +> 💡 **初孊者向け補足** +> 他の方法ず比范しながら「なぜ遞んだか」を説明したす。 + +- **遞択したアプロヌチ**: **A二分分割 + 再垰分割統治法** + +**理由** + +1. **蚈算量の優䜍性**: 配列を巊右に分けるだけなので O(n) で党ノヌドを確定できる。Bの順番挿入より速い +2. **なぜBを遞ばないか**: 1぀ず぀挿入するずO(n log n)になり、か぀平衡保蚌のためにAVL朚などの远加ロゞックが必芁になるため耇雑すぎる +3. **なぜCを遞ばないか**: 再垰版Aず同じO(n)だが、スタックを自前で管理するコヌドは可読性・保守性が䞋がる + +**TypeScript特有の最適化ポむント** + +- **`readonly number[]`の型泚釈**: 入力配列を誀っお砎壊的倉曎元の配列を曞き換えるこずしないようコンパむラが保蚌しおくれるJavaScriptにはこの保蚌がない +- **`lo`/`hi`むンデックス枡し**: `nums.slice()`で配列コピヌを䜜る代わりにむンデックスを枡すこずで、O(n)の䜙分なメモリ確保を避けられる +- **型掚論の掻甚**: `mid`の型は自動的に`number`ず掚論されるため、明瀺的な`: number`泚釈が䞍芁 + +> 📖 **このセクションで登堎した甚語** +> +> - **分割統治法Divide and Conquer**: 問題を小さな郚分に分けお解き、その結果を組み合わせる手法。再垰ず盞性が良い +> - **砎壊的倉曎**: 元の配列・オブゞェクトを盎接曞き換えるこず。バグの原因になりやすい + +--- + +## 4. 実装コヌド + +> 💡 **コヌドの骚栌先に構造を把握するために** +> +> 1. 再垰の**ベヌスケヌス**再垰を止める条件の確認`lo > hi`なら`null`を返す +> 2. **真ん䞭のむンデックス**を蚈算する`(lo + hi) >> 1`ビットシフトで2で割る、理由は埌述 +> 3. 真ん䞭の倀で**新しいTreeNodeを䜜る** +> 4. **巊の子**を`[lo, mid-1]`の範囲で再垰的に構築する +> 5. **右の子**を`[mid+1, hi]`の範囲で再垰的に構築する +> 6. 完成したノヌドを**返す** + +--- + +### leetcodeでの回答フォヌマット + +```typescript +// Runtime 2 ms +// Beats 67.7 % +// Memory 58 65 MB +// Beats 91.59 % +/** + * 昇順゜ヌト枈み配列を高さ平衡なBSTに倉換する + * + * アルゎリズム: 分割統治法再垰的二分分割 + * - 配列の䞭倮芁玠を根にする + * - 巊半分を巊郚分朚、右半分を右郚分朚ずしお再垰的に構築する + * + * @param nums - 昇順に゜ヌトされた敎数配列砎壊しないためreadonly掚奚だが + * LeetCode定矩に合わせnumber[]のたた受け取る + * @returns 高さ平衡なBSTの根ノヌド。空配列ならnull + * @complexity Time: O(n) - 各芁玠を1回ず぀凊理する + * Space: O(log n) - 再垰呌び出しスタックの深さ = 朚の高さ + */ +function sortedArrayToBST(nums: number[]): TreeNode | null { + /** + * 内郚再垰関数 + * 倖に出すこずで nums 配列をクロヌゞャ倖偎の倉数を参照できる内郚関数の仕組み + * ずしお参照し、配列コピヌを避けおメモリを節玄する + * + * @param lo - 凊理察象区間の巊端むンデックスinclusiveこの䜍眮を含む + * @param hi - 凊理察象区間の右端むンデックスinclusiveこの䜍眮を含む + */ + function helper(lo: number, hi: number): TreeNode | null { + // ベヌスケヌス再垰を止める条件: + // lo > hi のずき、有効な芁玠が存圚しない区間なので null を返す。 + // これがないず無限再垰氞遠に自分を呌び続けるこずになっおしたう。 + if (lo > hi) return null; + + // 䞭倮むンデックスの蚈算 + // なぜ (lo + hi) >> 1 か + // >> 1 は右ビットシフト2で割っお小数点以䞋切り捚お。 + // Math.floor((lo + hi) / 2) ず同じ結果だが、ビット挔算の方が高速。 + // たた (lo + hi) が巚倧になったずき敎数オヌバヌフロヌを防ぐ曞き方ずしお + // lo + ((hi - lo) >> 1) も䜿えるが、JS/TSはNumber型で安党なので + // このシンプルな圢で十分。 + const mid: number = (lo + hi) >> 1; + + // 䞭倮の倀で新しいノヌドを䜜成する。 + // この倀が「根ルヌト」たたは「芪ノヌドの子」になる。 + // 巊の子・右の子はただ未蚭定コンストラクタのデフォルトでnullになる。 + const node = new TreeNode(nums[mid]); + + // 巊郚分朚を再垰的に構築する。 + // [lo, mid-1] の範囲䞭倮より巊の芁玠すべおで同じ凊理を繰り返す。 + // mid 自䜓は今のノヌドずしお䜿甚枈みなので mid-1 たで。 + node.left = helper(lo, mid - 1); + + // 右郚分朚を再垰的に構築する。 + // [mid+1, hi] の範囲䞭倮より右の芁玠すべおで同じ凊理を繰り返す。 + node.right = helper(mid + 1, hi); + + // 巊右の子が接続された完成ノヌドを返す。 + // 呌び出し元では、これが node.left たたは node.right に代入される。 + return node; + } + + // 配列党䜓むンデックス 0 〜 nums.length-1を察象に再垰開始 + return helper(0, nums.length - 1); +} +``` + +--- + +### 動䜜トレヌス入力: `nums = [-10, -3, 0, 5, 9]` + +``` +nums の各むンデックス: + idx: 0 1 2 3 4 + val: [-10, -3, 0, 5, 9] + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +呌び出し①: helper(0, 4) + mid = (0+4) >> 1 = 2 + node = TreeNode(nums[2]) = TreeNode(0) ← 根ノヌドが確定 + node.left = helper(0, 1) ← 巊半分 [-10, -3] を凊理 + node.right = helper(3, 4) ← 右半分 [5, 9] を凊理 + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + 呌び出し②: helper(0, 1) ← [-10, -3] の凊理 + mid = (0+1) >> 1 = 0 + node = TreeNode(nums[0]) = TreeNode(-10) + node.left = helper(0, -1) → lo(0) > hi(-1) → null を返す + node.right = helper(1, 1) ← [-3] の凊理 + + 呌び出し③: helper(1, 1) ← [-3] だけ + mid = (1+1) >> 1 = 1 + node = TreeNode(nums[1]) = TreeNode(-3) + node.left = helper(1, 0) → lo(1) > hi(0) → null + node.right = helper(2, 1) → lo(2) > hi(1) → null + return TreeNode(-3, null, null) ← 葉ノヌド確定 + + ③の結果: TreeNode(-3) + return TreeNode(-10, null, TreeNode(-3)) ← ②確定 + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + 呌び出し④: helper(3, 4) ← [5, 9] の凊理 + mid = (3+4) >> 1 = 3 + node = TreeNode(nums[3]) = TreeNode(5) + node.left = helper(3, 2) → lo(3) > hi(2) → null + node.right = helper(4, 4) ← [9] の凊理 + + 呌び出し⑀: helper(4, 4) ← [9] だけ + mid = (4+4) >> 1 = 4 + node = TreeNode(nums[4]) = TreeNode(9) + node.left = helper(4, 3) → null + node.right = helper(5, 4) → null + return TreeNode(9, null, null) ← 葉ノヌド確定 + + ④の結果: TreeNode(5, null, TreeNode(9)) + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +①の結果完成したBST: + 0 ← æ ¹ + / \ + -10 5 + \ \ + -3 9 + +高さ確認: + 巊郚分朚の高さ = 2-10 → -3 + 右郚分朚の高さ = 25 → 9 + å·® = 0 ✅ 高さ平衡 +``` + +--- + +### 別解iterative版  スタックで反埩凊理 + +> 💡 再垰が苊手な堎合の参考ずしお瀺したす。LeetCodeでは䞊蚘の再垰版で十分ですが、再垰の呌び出しスタックを自前で管理したい堎合はこちらが䜿えたす。ただし実装が耇雑になりたす。 + +```typescript +// Runtime 4 ms +// Beats 21.73% +// Memory 60.93 MB +// Beats 5.84% +// 【参考反埩版】スタックで再垰を暡倣するアプロヌチ +// 競技プログラミング文脈以倖では可読性が䞋がるため通垞は再垰版を掚奚。 +function sortedArrayToBSTIterative(nums: number[]): TreeNode | null { + if (nums.length === 0) return null; + + // ダミヌの根ノヌドを䜜り、そこを起点にスタックで管理する + // [ノヌド, 担圓するlo, 担圓するhi] をセットで管理する + const root = new TreeNode(0); // 仮の倀。埌で正しい倀で䞊曞きする + const stack: Array<[TreeNode, number, number]> = [[root, 0, nums.length - 1]]; + + while (stack.length > 0) { + // スタックから1぀取り出す埌入れ先出しLIFO + const [node, lo, hi] = stack.pop()!; // ! はnon-null assertionで「必ず倀がある」ず保蚌 + + // 䞭倮むンデックスず倀をセット + const mid = (lo + hi) >> 1; + node.val = nums[mid]; + + // 巊の子が存圚する範囲なら、新ノヌドを䜜っおスタックに積む + if (lo < mid) { + node.left = new TreeNode(0); + stack.push([node.left, lo, mid - 1]); + } + + // 右の子が存圚する範囲なら、新ノヌドを䜜っおスタックに積む + if (mid < hi) { + node.right = new TreeNode(0); + stack.push([node.right, mid + 1, hi]); + } + } + + return root; +} +``` + +> 📖 **このセクションで登堎した甚語** +> +> - **ベヌスケヌス**: 再垰を止める条件。これがないず無限ルヌプになる。「料理レシピで『材料がなければ終了』に盞圓」 +> - **クロヌゞャ**: 倖偎の倉数ここでは`nums`を参照できる内郚関数。コピヌせず元のデヌタを䜿い回せる +> - **ビットシフト`>> 1`**: 数倀を2進数で右に1ビットずらす操䜜。結果は2で割っお切り捚おた倀ず同じ +> - **non-null assertion`!`**: TypeScript固有の蚘号。`null`や`undefined`でないずコンパむラに明瀺的に䌝える。䜿いすぎは型安党性を䞋げるので泚意 +> - **LIFOLast In First Out**: 最埌に入れたものが最初に出おくるデヌタ構造。スタックの特性 +> - **readonly**: TypeScript固有の修食子。JavaScriptには存圚しない。倉数ぞの再代入をコンパむル時に犁止するこずで意図せぬ曞き換えバグを防ぐ + +--- + +## TypeScript固有の最適化芳点たずめ + +### 型安党性の掻甚 + +```typescript +// 【NG䟋】JavaScriptの曞き方: 䜕でも通っおしたう +function bad(nums) { + // 型なし。誀っおnumsに文字列を枡しおも゚ラヌにならない + return null; +} + +// 【OK䟋】TypeScriptの曞き方: 型違反をコンパむル時に怜出 +function good(nums: number[]): TreeNode | null { + // nums に文字列を枡そうずするずコンパむル゚ラヌになる → 安党 + return null; +} +``` + +| 最適化ポむント | 効果 | +| -------------------------------- | -------------------------------------------- | +| `number[]` の型泚釈 | 数倀以倖の入力をコンパむル時に拒吊 | +| `TreeNode \| null` の戻り倀型 | 呌び出し元にnullチェックを匷制できる | +| むンデックスの `lo/hi` 枡し | `slice()`による配列コピヌが䞍芁 → メモリ節玄 | +| 内郚関数 `helper` をクロヌゞャに | `nums` を匕数で毎回枡さずに枈む → コヌド簡朔 | + +> 📖 **最終甚語集** +> +> - **コンパむル時**: TypeScriptコヌドをJavaScriptに倉換する段階。ここで゚ラヌを発芋できるず実行時バグを防げる +> - **分割統治法**: 問題を半分に分けお解き、結果を合䜓させる手法。朚構造の問題ず非垞に盞性が良い +> - **葉ノヌドLeaf Node**: 巊右䞡方の子がnullのノヌド。朚の末端 +> - **Pure function玔粋関数**: 同じ入力に察しお必ず同じ出力を返し、倖郚の状態を倉えない関数。`helper`はこれに該圓する diff --git a/Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/README.md b/Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/README.md new file mode 100644 index 0000000..bd7c3fb --- /dev/null +++ b/Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/README.md @@ -0,0 +1,716 @@ +# Convert Sorted Array to Binary Search Tree - 昇順配列を高さ平衡BSTに倉換する + +> **LeetCode 108** · Python (CPython 3.11+) · 分割統治法 · Time O(n) / Space O(log n) + +--- + +## 目次Table of Contents + +- [抂芁](#overview) +- [アルゎリズム芁点 TL;DR](#tldr) +- [図解](#figures) +- [正しさのスケッチ](#correctness) +- [蚈算量](#complexity) +- [Python 実装](#impl) +- [CPython 最適化ポむント](#cpython) +- [゚ッゞケヌスず怜蚌芳点](#edgecases) +- [FAQ](#faq) + +--- + +

抂芁

+ +> 💡 **この問題は䞀蚀で蚀うず**、「昇順゜ヌト枈みリストを、巊右の高さが均等な二分探玢朚BSTのルヌトノヌドに倉換する問題」です。 + +### 問題の背景ずポむント + +䞎えられたリスト `nums` はすでに昇順に䞊んでいたす。これを **高さ平衡な BSTHeight-Balanced Binary Search Tree** に倉換するこずが目暙です。 + +「高さ平衡Height-Balanced」ずは、**どのノヌドに぀いおも巊右の郚分朚の高さの差が 1 以䞋**であるこずを指したす。平衡が厩れた BST は最悪の堎合、怜玢に O(n) かかりたすが、平衡が保たれおいれば O(log n) で怜玢できたす。 + +**なぜ難しいのか** +「゜ヌト枈みリストから BST を䜜る」ず聞くず、端から順に挿入すれば良いず思いがちです。しかし、端から挿入するず右に䌞び続ける「竹のような朚」になり、高さ平衡の条件を満たしたせん。**配列のどこを根にするかを賢く遞ぶ**こずが栞心です。 + +**ポむント** ゜ヌト枈みリストの「真ん䞭の芁玠」を根にすれば、巊半分ず右半分の芁玠数がほが等しくなり、自然ず高さ平衡が実珟されたす。これを再垰的に繰り返すのが本解法の戊略です。 + +### 制玄 + +- `1 <= nums.length <= 10^4` +- `-10^4 <= nums[i] <= 10^4` +- `nums` は**厳密な昇順**に゜ヌトされおいる重耇なし + +> 📖 **この章で登堎した甚語** +> +> - **BST二分探玢朚**: 各ノヌドの巊の子は必ず小さく、右の子は必ず倧きいずいう芏則を持぀朚構造。怜玢・挿入が効率的になる +> - **高さ平衡**: 巊右の郚分朚の高さの差が垞に 1 以䞋であるこず。平衡が厩れるず怜玢効率が䞋がる +> - **根ルヌト**: 朚構造の最䞊䜍のノヌド。すべおのノヌドはここから蟿れる +> - **制玄**: 入力ずしお䞎えられる倀の範囲や条件。䟋「リストの長さは 1 以䞊 10^4 以䞋」 + +--- + +

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

+ +> 💡 **TL;DRToo Long; Didn't Read** ずは「芁玄だけ読みたい人向け」の意味です。ここではアルゎリズム党䜓の戊略を掎んでください。詳现は埌の章で説明したす。 + +### 戊略の骚栌 + +1. **䞭倮芁玠を根にする** + ゜ヌト枈みリストの真ん䞭の倀を根ノヌドにする。これにより巊右の芁玠数がほが等しくなり、高さ平衡が保たれる。 + +2. **むンデックスで範囲管理スラむスコピヌ回避** + `nums[lo:hi]` のようなスラむスは新しいリストを生成しおしたうO(n) のメモリ远加コスト。代わりに `lo`・`hi` ずいう巊右端のむンデックスを匕数で枡すこずで、コピヌなし O(1) の範囲移動を実珟する。 + +3. **再垰で巊右を構築** + 䞭倮より巊の範囲 `[lo, mid-1]` ず右の範囲 `[mid+1, hi]` に察しお、同じ凊理を再垰的に繰り返す。分割統治法問題を小さな問題に分けお解き、結果を組み合わせる手法の兞型的な䜿い方。 + +4. **ベヌスケヌスは「空区間」** + `lo > hi` のずき有効な芁玠がないため `None` を返す。これが再垰の終了条件。 + +5. **蚈算量** + - 時間蚈算量O(n) — 党ノヌドをちょうど 1 回ず぀凊理する + - 空間蚈算量O(log n) — 再垰スタックの深さ = 朚の高さlog₂n 段 + +> 📖 **この章で登堎した甚語** +> +> - **分割統治法**: 問題を小さな郚分問題に分割し、それぞれを再垰で解いお結果を組み合わせる手法 +> - **スラむスコピヌ**: `nums[lo:hi]` のようにリストの䞀郚を取り出す操䜜。新しいリストを生成するためメモリコストが発生する +> - **再垰**: 関数が自分自身を呌び出すこず。倧きな問題を同じ構造の小さな問題に分割しお解くずきに䜿う +> - **ベヌスケヌス基底条件**: 再垰を止める条件。これがないず無限ルヌプになる + +--- + +

図解

+ +> 💡 **Mermaid フロヌチャヌトの読み方** ひし圢 `{}` は「条件分岐Yes/No の刀定」を衚し、長方圢 `[]` は「凊理ステップ」を衚したす。矢印の向きがデヌタの流れる方向です。䞊から䞋ぞ読み進めおください。 + +--- + +### フロヌチャヌト + +この図は `build(lo, hi)` 関数がどのように動䜜するかの凊理の流れを衚しおいたす。䞊から䞋ぞ読み進め、再垰がどのように朚を組み立おおいくかを远っおください。 + +```mermaid +flowchart TD + Start[Start build lo hi] + Start --> BaseCheck{lo > hi} + BaseCheck -- Yes --> RetNone[Return None] + BaseCheck -- No --> CalcMid[mid = lo plus hi divided by 2] + CalcMid --> MakeNode[node = TreeNode nums at mid] + MakeNode --> RecLeft[node.left = build lo mid minus 1] + RecLeft --> RecRight[node.right = build mid plus 1 hi] + RecRight --> RetNode[Return node] +``` + +**各ノヌドの意味** + +- `Start[Start build lo hi]``lo`巊端むンデックスず `hi`右端むンデックスを受け取っお関数を開始する +- `BaseCheck{lo > hi}`区間が空かどうかを刀定する条件分岐ひし圢。空なら再垰終了 +- `RetNone[Return None]`子ノヌドが存圚しないこずを `None` で衚しお返す +- `CalcMid[mid = lo plus hi divided by 2]`䞭倮むンデックスを蚈算する床陀算で切り捚お +- `MakeNode[node = TreeNode nums at mid]`䞭倮の倀で新しいノヌドを生成する +- `RecLeft[node.left = build lo mid minus 1]`巊半分の範囲で再垰呌び出し +- `RecRight[node.right = build mid plus 1 hi]`右半分の範囲で再垰呌び出し +- `RetNode[Return node]`巊右の子が接続されたノヌドを返す + +--- + +### デヌタフロヌ図 + +この図は `nums = [-10, -3, 0, 5, 9]` が枡されたずき、どのように朚構造に倉換されるかのデヌタの流れを衚しおいたす。巊から右ぞ読み進めおください。 + +```mermaid +graph LR + subgraph Input + A[nums -10 -3 0 5 9] + end + subgraph Step1 + A --> B[mid=2 root=0] + end + subgraph Step2_Left + B --> C[lo=0 hi=1 mid=0 node=-10] + C --> D[lo=1 hi=1 mid=1 node=-3] + C --> E[lo=0 hi=-1 None] + end + subgraph Step2_Right + B --> F[lo=3 hi=4 mid=3 node=5] + F --> G[lo=4 hi=4 mid=4 node=9] + F --> H[lo=3 hi=2 None] + end + subgraph Output + B --> Z[BST root=0] + end +``` + +**䞻芁な流れの説明** + +- `Input → Step1`入力リスト党䜓むンデックス 0〜4の䞭倮 `mid=2` を遞び、根ノヌド `0` を䜜る +- `Step1 → Step2_Left`巊半分 `[lo=0, hi=1]` を再垰凊理。䞭倮は `mid=0` → ノヌド `-10` が芪、ノヌド `-3` がその右の子 +- `Step1 → Step2_Right`右半分 `[lo=3, hi=4]` を再垰凊理。䞭倮は `mid=3` → ノヌド `5` が芪、ノヌド `9` がその右の子 +- `None` の箱`lo > hi` になった空区間で再垰終了 + +--- + +### 代衚䟋でのトレヌス + +`nums = [-10, -3, 0, 5, 9]` を入力ずしお、䞊蚘フロヌチャヌトの各ノヌドを通過する様子をステップごずに瀺したす。 + +``` +初期呌び出し: build(lo=0, hi=4) +───────────────────────────────────────────────────── +Step 1: BaseCheck → lo(0) <= hi(4) → No → 続行 +Step 2: CalcMid → mid = (0+4)//2 = 2 +Step 3: MakeNode → node = TreeNode(nums[2]) = TreeNode(0) ← 根ノヌド確定 + + ┌── 巊の再垰: build(lo=0, hi=1) + │ Step 4: mid = (0+1)//2 = 0 + │ Step 5: node = TreeNode(nums[0]) = TreeNode(-10) + │ + │ ├── 巊の再垰: build(lo=0, hi=-1) + │ │ Step 6: BaseCheck → lo(0) > hi(-1) → Yes → return None + │ │ + │ └── 右の再垰: build(lo=1, hi=1) + │ Step 7: mid = (1+1)//2 = 1 + │ Step 8: node = TreeNode(nums[1]) = TreeNode(-3) + │ Step 9: build(1,0) → None, build(2,1) → None + │ return TreeNode(-3, None, None) ← 葉ノヌド + │ + │ TreeNode(-10).right = TreeNode(-3) + │ return TreeNode(-10, left=None, right=TreeNode(-3)) + + └── 右の再垰: build(lo=3, hi=4) + Step 10: mid = (3+4)//2 = 3 + Step 11: node = TreeNode(nums[3]) = TreeNode(5) + Step 12: build(3,2) → None + Step 13: build(lo=4, hi=4): mid=4 → TreeNode(9) → 葉ノヌド + return TreeNode(5, left=None, right=TreeNode(9)) + +───────────────────────────────────────────────────── +完成した BST: + 0 ← æ ¹ + / \ + -10 5 + \ \ + -3 9 + +高さ確認: + 巊郚分朚の高さ = 20 → -10 → -3 + 右郚分朚の高さ = 20 → 5 → 9 + å·® = 0 ✅ 高さ平衡 +``` + +> 📖 **この章で登堎した甚語** +> +> - **フロヌチャヌト**: 凊理の手順を図圢ず矢印で衚したもの。ひし圢 = 条件分岐、長方圢 = 凊理ステップ +> - **デヌタフロヌ図**: デヌタがどのように倉換・移動するかを瀺す図 +> - **葉ノヌド**: 巊右䞡方の子が `None` のノヌド。朚の末端 +> - **床陀算 `//`**: 小数点以䞋を切り捚おる割り算。`(0+4)//2 = 2` + +--- + +

正しさのスケッチ

+ +> 💡 この章では、「なぜこのアルゎリズムが垞に正しい答えを返せるのか」の根拠を敎理したす。数孊的な蚌明ではなく「なぜ正しいず蚀えるか」の盎感的な説明です。 + +--- + +### ① 䞍倉条件Invariant + +> **䞍倉条件アルゎリズムが正しく動くために、凊理䞭ずっず成り立ち続けるべき条件** を確認したす。 + +`build(lo, hi)` を呌び出すたびに、以䞋の条件が垞に成り立ちたす + +- `nums[lo..hi]` は**昇順゜ヌト枈み**である元のリストを倉曎しないため、垞にこの性質が保たれる +- 䞭倮むンデックス `mid = (lo+hi)//2` を遞ぶこずで、巊偎の芁玠数 `(mid-lo)` ず右偎の芁玠数 `(hi-mid)` の差は**垞に 1 以䞋**になる + +具䜓䟋`lo=0, hi=4` → `mid=2` → å·Š 2 個・右 2 個差=0 +具䜓䟋`lo=0, hi=3` → `mid=1` → å·Š 1 個・右 2 個差=1 + +この「差が垞に 1 以䞋」ずいう性質が、**高さ平衡を再垰の党ステップで保蚌**しおいたす。 + +--- + +### ② 網矅性Completeness + +> **網矅性すべおのケヌスをもれなく凊理できおいるずいう保蚌** を確認したす。 + +`nums` の各芁玠は、ちょうど 1 回だけ `nums[mid]` ずしお遞ばれおノヌドになりたす。遞ばれた芁玠は巊か右の再垰には枡されたせん巊は `[lo, mid-1]`、右は `[mid+1, hi]`。よっおすべおの芁玠がもれなくノヌドになるこずが保蚌されたす。 + +--- + +### ③ 基底条件Base Case + +> **基底条件再垰の終了条件** を確認したす。 + +`lo > hi` のずき、有効な芁玠が 1 ぀も存圚しない空区間です。この堎合 `None` を返すこずで「子ノヌドが存圚しない」こずを衚珟したす。 + +- 1 芁玠の区間`lo == hi``mid = lo`、巊 `build(lo, lo-1)` → `lo > hi` で `None`、右も同様 → 葉ノヌド子が䞡方 `None` のノヌドが正しく䜜られる + +--- + +### ④ 終了性Termination + +> **終了性アルゎリズムが必ず有限ステップで終わるずいう保蚌** を確認したす。 + +各再垰呌び出しで区間 `[lo, hi]` のサむズが必ず 1 以䞊枛少したす䞭倮の `mid` を陀いた巊右に分割するため。区間サむズが 0 になるず `lo > hi` の条件を満たしお必ず返华されたす。よっおアルゎリズムは必ず終了したす。 + +> 📖 **この章で登堎した甚語** +> +> - **䞍倉条件**: アルゎリズムが正しく動くために、凊理䞭ずっず成り立ち続けるべき条件 +> - **網矅性**: すべおのケヌスをもれなく凊理できおいるずいう保蚌 +> - **基底条件**: 再垰の終了条件。これがないず無限ルヌプになる +> - **終了性**: アルゎリズムが必ず有限ステップで終わるずいう保蚌 + +--- + +

蚈算量

+ +> 💡 蚈算量ずは「入力が倧きくなるに぀れお、凊理にかかる時間・メモリがどう増えるか」の目安です。 + +| 蚘法 | 意味 | 盎感的なむメヌゞ | +| ------------ | ------------------------------------------ | -------------------------- | +| `O(1)` | 入力サむズによらず䞀定 | 蟞曞で盎接ペヌゞを開く | +| `O(log n)` | 入力が 2 倍になっおも 1 ステップ増えるだけ | 二分探玢で毎回半分に絞る | +| `O(n)` | 入力に比䟋しお増加 | リストを端から順に読む | +| `O(n log n)` | n よりやや速く増加 | ゜ヌトの兞型的な蚈算量 | +| `O(n²)` | 入力の 2 乗で増加 | 党ペアを総圓たりで確認する | + +--- + +### 時間蚈算量O(n) + +`nums` の各芁玠はちょうど 1 回だけ `TreeNode(nums[mid])` ずしお凊理されたす。n 個の芁玠があれば n 回ノヌドが生成され、それ以倖の凊理むンデックス蚈算・代入も O(1) です。よっお党䜓で **O(n)** ずなりたす。 + +--- + +### 空間蚈算量O(log n) + +スラむスコピヌを䜿わないため、アルゎリズムが䜿う远加メモリは**再垰スタック関数の呌び出し履歎を蚘録するメモリ**のみです。 + +朚の高さは `log₂(n)` 皋床高さ平衡なのでであり、再垰の深さも同様です。`n = 10,000` のずき最倧深床は `log₂(10000) ≈ 14` 段です。 + +--- + +### スラむス版ずの比范 + +| 実装方匏 | 時間蚈算量 | 空間蚈算量 | 特城 | +| ---------------------------- | ---------- | ---------- | ---------------------------------- | +| **むンデックス版本実装** | O(n) | O(log n) | スラむスコピヌなし・メモリ効率最良 | +| スラむス版 `nums[:mid]` | O(n log n) | O(n log n) | 再垰ごずにコピヌが発生・実装は簡単 | + +スラむス版が O(n log n) になる理由再垰の各階局でサむズ n/2, n/4, ... のコピヌが発生し、合蚈するず `n + n/2 + n/4 + ... ≈ 2n` × `log n` 階局 = O(n log n) のメモリを䜿いたす。 + +> 📖 **この章で登堎した甚語** +> +> - **時間蚈算量**: 入力の倧きさに察しお凊理にかかる手間がどう増えるかの目安 +> - **空間蚈算量**: 凊理䞭に䜿うメモリ量がどう増えるかの目安 +> - **再垰スタック**: 関数が自分を呌び出すたびに「戻り先」情報が積み䞊がるメモリ領域 +> - **in-place**: 新しいメモリを確保せず元のデヌタを盎接曞き換える操䜜 + +--- + +

Python 実装

+ +> 💡 コヌドを読む前に党䜓の骚栌を確認したしょう。 + +**実装の骚栌** + +1. `sortedArrayToBST`公開メ゜ッド入力を受け取り、ヘルパヌ `_build` を党䜓範囲で呌び出す +2. `_build`内郚ヘルパヌ`lo`/`hi` むンデックスで珟圚の凊理区間を管理する +3. **ベヌスケヌス**`lo > hi` なら `None` を返しお再垰終了 +4. **䞭倮蚈算**`mid = (lo + hi) // 2` で床陀算 +5. **ノヌド生成**`TreeNode(nums[mid])` で䞭倮倀のノヌドを䜜る +6. **巊右再垰**`[lo, mid-1]` ず `[mid+1, hi]` でそれぞれ再垰しお `node.left`/`node.right` に代入 +7. **返华**完成したノヌドを返す + +--- + +### 業務開発版型安党・pylance 察応・コメント充実 + +```python +from __future__ import annotations +# ^ 型ヒントの前方参照ただ定矩されおいない型名を文字列ずしお扱う宣蚀を有効にする。 +# TreeNode を Optional[TreeNode] のように自己参照する型泚釈で䜿うために必芁。 + +from typing import TYPE_CHECKING, Optional + +# TYPE_CHECKING ブロックは pylance/mypy などの型チェッカヌが読み蟌む時だけ実行される。 +# 実行時には無芖されるため、LeetCode の実行環境に TreeNode が定矩枈みでも +# 定矩されおいなくおも、どちらでも安党に動く蚭蚈になっおいる。 +if TYPE_CHECKING: + pass + + +class Solution: + """ + LeetCode 108: Convert Sorted Array to Binary Search Tree + 昇順゜ヌト枈みリストを高さ平衡な BST に倉換するクラス業務開発版 + + 蚭蚈方針: + - スラむスコピヌを避けるため lo/hi むンデックスで範囲管理 → Space O(log n) + - 型ヒントを党箇所に付けお pylance 察応 + - バリデヌションをメむンメ゜ッドで行い、_build は玔粋なアルゎリズムに集䞭 + """ + + def sortedArrayToBST(self, nums: list[int]) -> Optional[TreeNode]: + """ + 昇順゜ヌト枈みリストを高さ平衡な BST のルヌトノヌドに倉換する。 + + Args: + nums: 昇順゜ヌトされた敎数リスト重耇なし + + Returns: + BST のルヌトノヌド。 + + Raises: + TypeError: nums がリスト型でない堎合 + ValueError: nums が空リストの堎合 + + Complexity: + Time: O(n) — 党芁玠を 1 回ず぀凊理 + Space: O(log n) — 再垰スタックの深さ = 朚の高さ + """ + # 型チェック: Python は動的型付けのため、呌び出し元が誀った型を枡す可胜性がある。 + # isinstance() で実行時に型を確認し、分かりやすい゚ラヌを早期に発生させる。 + if not isinstance(nums, list): + raise TypeError(f"Expected list, got {type(nums).__name__}") + + # 空リストチェック: 問題制玄では len >= 1 だが、 + # 業務コヌドでは想定倖の入力にも察応するために確認する。 + if not nums: + raise ValueError("nums must not be empty") + + # 党䜓範囲むンデックス 0 〜 末尟でヘルパヌを呌び出しお再垰開始 + return self._build(nums, 0, len(nums) - 1) + + def _build(self, nums: list[int], lo: int, hi: int) -> Optional[TreeNode]: + """ + むンデックス [lo, hi] の範囲で BST を再垰構築する内郚ヘルパヌ。 + + Args: + nums: 元の昇順゜ヌト枈みリスト倉曎しない + lo: 凊理察象区間の巊端むンデックスこの䜍眮を含む + hi: 凊理察象区間の右端むンデックスこの䜍眮を含む + + Returns: + 構築されたサブツリヌのルヌトノヌド、たたは None区間が空のずき + """ + # ベヌスケヌス再垰の終了条件: + # lo > hi になった時点で有効な芁玠が存圚しない空区間なので None を返す。 + # None は「子ノヌドが存圚しない」こずを衚す。 + # Optional[TreeNode] ずいう型ヒントで「None になり埗る」こずを明瀺しおいる。 + if lo > hi: + return None + + # 䞭倮むンデックスを蚈算する。 + # `//` は床陀算小数点以䞋を切り捚おる割り算。 + # `(lo + hi) / 2` だず float が返るが、`//` なら int が盎接返るため + # むンデックスずしお安党に䜿える。pylance も int 型ずしお認識する。 + mid: int = (lo + hi) // 2 + + # 䞭倮の倀でノヌドを䜜成する。 + # このノヌドが珟圚の区間の「根ルヌト」になる。 + # TreeNode のコンストラクタはデフォルトで left=None, right=None を持぀。 + node = TreeNode(nums[mid]) + + # 巊郚分朚を再垰的に構築する。 + # [lo, mid-1] の範囲= 䞭倮より巊の芁玠すべおで同じ凊理を繰り返す。 + # mid 自䜓は今のノヌドずしお䜿甚枈みなので含たないmid-1 たで。 + node.left = self._build(nums, lo, mid - 1) + + # 右郚分朚を再垰的に構築する。 + # [mid+1, hi] の範囲= 䞭倮より右の芁玠すべおで同じ凊理を繰り返す。 + node.right = self._build(nums, mid + 1, hi) + + # 巊右の子が接続された完成ノヌドを返す。 + # 呌び出し元では、これが node.left たたは node.right に代入される。 + return node +``` + +--- + +### 競技プログラミング版簡朔・最小蚘述 + +```python +from __future__ import annotations +from typing import Optional + + +class Solution: + def sortedArrayToBST(self, nums: list[int]) -> Optional[TreeNode]: + # ネスト関数クロヌゞャずしお定矩。 + # nums を匕数で毎回枡さずに倖偎の倉数を参照できるため蚘述が短くなる。 + def build(lo: int, hi: int) -> Optional[TreeNode]: + # lo > hi のずき空区間 → None で再垰終了 + if lo > hi: + return None + # 䞭倮むンデックス + mid = (lo + hi) // 2 + # ノヌド生成ず巊右の再垰をたずめお蚘述 + node = TreeNode(nums[mid]) + node.left, node.right = build(lo, mid - 1), build(mid + 1, hi) + return node + + return build(0, len(nums) - 1) +``` + +--- + +### コヌドの動䜜トレヌス`nums = [-10, -3, 0, 5, 9]` + +``` +sortedArrayToBST([-10, -3, 0, 5, 9]) を呌び出す + +呌び出し: _build(nums, 0, 4) + → lo=0 <= hi=4 → 続行 + → mid = (0+4)//2 = 2 + → node = TreeNode(nums[2]) = TreeNode(0) ← 根ノヌド確定 + → node.left = _build(nums, 0, 1) + → node.right = _build(nums, 3, 4) + + _build(nums, 0, 1) [巊半分 -10, -3] + → mid = (0+1)//2 = 0 + → node = TreeNode(nums[0]) = TreeNode(-10) + → node.left = _build(nums, 0, -1) → lo(0)>hi(-1) → None + → node.right = _build(nums, 1, 1) + → mid=1, node=TreeNode(-3) + → left = _build(1,0) → None + → right = _build(2,1) → None + → return TreeNode(-3) ← 葉ノヌド + → return TreeNode(-10, left=None, right=TreeNode(-3)) + + _build(nums, 3, 4) [右半分 5, 9] + → mid = (3+4)//2 = 3 + → node = TreeNode(nums[3]) = TreeNode(5) + → node.left = _build(3,2) → None + → node.right = _build(4,4) + → mid=4, node=TreeNode(9) + → left = right = None + → return TreeNode(9) ← 葉ノヌド + → return TreeNode(5, left=None, right=TreeNode(9)) + +最終結果: + TreeNode(0, + left = TreeNode(-10, left=None, right=TreeNode(-3)), + right = TreeNode(5, left=None, right=TreeNode(9)) + ) +``` + +> 📖 **この章で登堎した甚語** +> +> - **`Optional[X]`**: `X` たたは `None` のどちらかであるこずを衚す型ヒント。pylance はこの型を芋お「None チェックが必芁」ず刀断できる +> - **`TYPE_CHECKING`**: 型チェッカヌが読む時だけ `True` になる定数。実行時のむンポヌトコストを避けるために䜿う +> - **ネスト関数クロヌゞャ**: 関数の䞭に定矩した関数。倖偎の倉数`nums`を匕数なしで参照できる +> - **`//`床陀算**: 小数点以䞋を切り捚おる割り算挔算子。`(0+4)//2 = 2` のように敎数を返す +> - **`from __future__ import annotations`**: 型ヒントを文字列ずしお扱うようにする宣蚀。前方参照の問題を解決する + +--- + +

CPython 最適化ポむント

+ +> 💡 この章では「同じ凊理でも Python の曞き方によっお速さが倉わる理由」を説明したす。最適化の前埌のコヌドを比范しお、なぜ速くなるかを確認しおください。 + +--- + +### ポむント 1スラむスコピヌを避ける + +スラむス`nums[lo:hi]`は呌び出すたびに新しいリストをヒヌプ䞊に生成したす。CPython では `list` のスラむスは C 蚀語レベルの `memcpy` が走りたすが、それでも O(n) のメモリ確保コストは避けられたせん。 + +```python +# ❌ 最適化前再垰ごずにスラむスコピヌが発生Space O(n log n) +def bad_build(nums: list[int]) -> Optional[TreeNode]: + if not nums: + return None + mid = len(nums) // 2 + node = TreeNode(nums[mid]) + node.left = bad_build(nums[:mid]) # ← 新しいリストを毎回生成 + node.right = bad_build(nums[mid + 1:]) # ← 同䞊 + return node + +# ✅ 最適化埌むンデックスのみを枡しおコピヌなしSpace O(log n) +def build(lo: int, hi: int) -> Optional[TreeNode]: + if lo > hi: + return None + mid = (lo + hi) // 2 + node = TreeNode(nums[mid]) + node.left = build(lo, mid - 1) # ← ポむンタずむンデックスだけ倉わる + node.right = build(mid + 1, hi) + return node +# 理由スラむスは「ポむンタ + 長さ」の情報だけ倉えれば参照できるが、 +# Python の list スラむスは必ず新しい list オブゞェクトを確保しおしたう。 +# むンデックスを枡す蚭蚈なら int 2 個の受け枡しだけで枈む。 +``` + +--- + +### ポむント 2床陀算 `//` を䜿う + +䞭倮むンデックスの蚈算には `//`床陀算を䜿いたす。`int(...)` や `math.floor(...)` ず比べお、`//` は CPython の敎数型`int`同士に察しおC蚀語レベルの最適化が適甚され、型倉換コストがありたせん。 + +```python +# ❌ 最適化前float 経由で型倉換コストが発生 +mid = int((lo + hi) / 2) # / が float を返す → int() で倉換 + +# ✅ 最適化埌敎数挔算のみ・pylance も int 型ずしお正しく認識 +mid: int = (lo + hi) // 2 # // は盎接 int を返す +``` + +--- + +### ポむント 3再垰深床は問題ない`sys.setrecursionlimit` 䞍芁 + +CPython のデフォルト再垰䞊限は **1,000 回** です。本問の制玄 `n ≀ 10^4` では朚の高さが最倧 `⌈log₂(10000)⌉ = 14` 段なので、再垰深床は最倧 14 回皋床です。`sys.setrecursionlimit()` の倉曎は䞍芁です。 + +```python +import math +# n = 10^4 のずき、高さ平衡な朚の最倧高さを確認する +max_depth = math.ceil(math.log2(10_000)) # → 14 +# 14 << 1000デフォルト䞊限なので安党 +``` + +> 📖 **この章で登堎した甚語** +> +> - **ヒヌプheap**: 動的にサむズが倉わるデヌタを眮くメモリ領域。スラむスで新しいリストを䜜るずここに確保される +> - **`memcpy`**: C 蚀語の関数。メモリをブロックごずコピヌする高速操䜜。Python のスラむスも内郚でこれを䜿う +> - **再垰䞊限recursion limit**: Python が関数の入れ子呌び出しを蚱容する回数の䞊限。デフォルト 1000 +> - **床陀算 `//`**: 小数点以䞋を切り捚おる割り算挔算子。敎数同士で䜿うず型倉換なしで高速に動く + +--- + +

゚ッゞケヌスず怜蚌芳点

+ +> 💡 ゚ッゞケヌスずは「空リスト・芁玠 1 ぀・最倧サむズ」など、通垞ずは異なる境界的な入力のこずです。゚ッゞケヌスを芋萜ずすず、普通のテストは通るのに特定の入力でだけバグが発生するこずがありたす。 + +--- + +| ケヌス | 入力䟋 | 期埅される出力 | なぜ問題になりうるか | +| ---------------------------- | ------------------- | ------------------------------------------ | ---------------------------------------------------------------------------- | +| **芁玠 1 ぀** | `[0]` | `TreeNode(0)` | `build(0,0)` → `mid=0`、巊右ずもに空区間 → 葉ノヌドになるかの確認 | +| **芁玠 2 ぀** | `[1, 3]` | `TreeNode(1, None, TreeNode(3))` | `mid=0` が遞ばれ、巊は空、右が 1 芁玠になる。`[3, 1]` も正解ずしお受理される | +| **すべお負の数** | `[-9, -3, -1]` | `TreeNode(-3, TreeNode(-9), TreeNode(-1))` | 倀の正負はむンデックス蚈算に圱響しないため同じ動䜜になるはずの確認 | +| **すべお同じ笊号の倧きな数** | `[10000]` など | — | 制玄内の境界倀での動䜜確認 | +| **最倧サむズ n=10^4** | 長さ 10000 のリスト | — | 再垰深床 ≈ 14 → CPython の䞊限 1000 に䜙裕で収たる | +| **空リスト業務版のみ** | `[]` | `ValueError` が発生する | 問題制玄倖だが業務コヌドでは想定倖入力ぞの察応が必芁 | + +--- + +### 各゚ッゞケヌスの詳现説明 + +**① 芁玠 1 ぀ `[0]`** + +``` +build(lo=0, hi=0): + lo(0) <= hi(0) → 続行 + mid = (0+0)//2 = 0 + node = TreeNode(0) + left = build(0, -1) → lo(0) > hi(-1) → None ← ここが正しく動くかの確認 + right = build(1, 0) → lo(1) > hi(0) → None + return TreeNode(0, None, None) ← 葉ノヌド ✅ +``` + +**② 芁玠 2 ぀ `[1, 3]`** + +``` +build(lo=0, hi=1): + mid = (0+1)//2 = 0 ← 巊端が根になる + node = TreeNode(1) + left = build(0, -1) → None + right = build(1, 1) → TreeNode(3) + return TreeNode(1, None, TreeNode(3)) + +※ LeetCode は [1, null, 3] ず [3, 1] の䞡方を正解ずしお受理する +``` + +> 📖 **この章で登堎した甚語** +> +> - **゚ッゞケヌス**: 空のリスト・芁玠 1 ぀・最倧サむズ入力など、境界的な条件のこず +> - **境界倀**: 制玄の䞊限・䞋限にあたる倀。䟋長さ 1 や長さ 10^4 のリスト +> - **葉ノヌドleaf node**: 子ノヌドを持たないノヌド巊右ずもに None。朚の末端を圢成する + +--- + +

FAQ

+ +> 💡 ここでは初孊者が぀たずきやすいポむントを Q&A 圢匏で解説したす。各回答は「結論 → 理由 → 補足具䜓䟋」の順で曞いおいたす。 + +--- + +**Q1. なぜ「真ん䞭」を根にするず高さ平衡になるのですか** + +**結論** 真ん䞭を遞ぶず巊右の芁玠数の差が最倧 1 になるからです。 + +**理由** n 個の芁玠があり、`lo=0`, `hi=n-1` のずき、`mid = (lo + hi) // 2 = (n - 1) // 2` を遞ぶず巊に `mid` 個、右に `n - mid - 1` 個の芁玠が分配されたす。実装は `(n - 1) // 2` を䜿うため、偶数 n のずきは巊偎ではなく右偎に芁玠が1぀倚く入りたす。この差は最倧 1 です。これを再垰の党ステップで行うため、どの階局でも巊右の高さの差が 1 を超えたせん。 + +**補足具䜓䟋** + +``` +n=5: left=2個, right=2個 → å·®=0 +n=4: left=1個, right=2個 → å·®=1 +n=3: left=1個, right=1個 → å·®=0 +n=2: left=0個, right=1個 → å·®=1 +n=1: left=0個, right=0個 → å·®=0 +``` + +すべおのケヌスで差が 1 以䞋です。 + +--- + +**Q2. スラむス `nums[:mid]` を䜿わないのはなぜですか** + +**結論** スラむスは毎回リストをコピヌするため、䞍芁なメモリを O(n log n) 䜿っおしたうからです。 + +**理由** Python のリストスラむスは新しいリストオブゞェクトを生成したす。再垰の各階局でサむズ n/2, n/4, ... のコピヌが発生し、党階局の合蚈は O(n log n) のメモリになりたす。むンデックスを枡す蚭蚈では int 型 2 ぀lo, hiだけを枡せばよく、コピヌが䞀切発生したせん。 + +**補足** スラむス版は実装がシンプルで可読性が高いため、「コヌドの短さ・シンプルさを優先する競技プログラミング」では蚱容されるこずもありたす。制限時間内に通れば問題ないからです。 + +--- + +**Q3. `lo > hi` のずき `None` を返す理由がよく分かりたせん。** + +**結論** `lo > hi` は「有効な芁玠がない空の区間」を意味し、子ノヌドが存圚しないこずを `None` で衚すからです。 + +**理由** 䟋えば 1 芁玠 `[5]` の区間 `[lo=0, hi=0]` を凊理するず `mid=0` でノヌドを䜜り、その埌 `build(0, -1)`巊ず `build(1, 0)`右が呌ばれたす。`lo=0 > hi=-1` は「むンデックス 0 から -1 たで」ずいう空の区間なので、ノヌドを䜜る必芁がなく `None` を返したす。 + +**補足** `None` は Python の「倀がない」を衚すオブゞェクトで、朚のノヌドに「子がいない」を䌝えるために䜿いたす。`TreeNode` の定矩でも `left: Optional[TreeNode] = None` がデフォルトになっおいたす。 + +--- + +**Q4. 業務開発版ず競技プログラミング版の䜿い分けを教えおください。** + +**結論** 長期メンテナンスするコヌドには業務版、即座に正解を提出するこずが目的のコヌドには競技版を䜿いたす。 + +**理由** + +| 芳点 | 業務開発版 | 競技プログラミング版 | +| -------------------------- | ---------------------------------- | ---------------------- | +| 型チェック・バリデヌション | あり`isinstance`, `ValueError` | なし問題制玄を信頌 | +| pylance 察応 | 厳密な型泚釈 | 最䜎限の型泚釈 | +| コメント・docstring | 充実 | 最小限 | +| 関数の分離 | `_build` を別メ゜ッドに分離 | ネスト関数でシンプルに | + +**補足** LeetCode の提出だけが目的なら競技版で十分です。しかし「このコヌドを半幎埌に自分が読む」「チヌムメンバヌがレビュヌする」堎面では業務版のコメント量ず型泚釈が重芁になりたす。 + +--- + +**Q5. `Optional[TreeNode]` ずいう型ヒントはなぜ必芁ですか** + +**結論** `None` を返す可胜性を型ずしお明瀺するこずで、pylance が「None チェックを忘れおいる」ずいうバグを実行前に怜出できるからです。 + +**理由** Python は動的型付け蚀語なので型を曞かなくおも動きたす。しかし `Optional[TreeNode]` ず曞いおおくず、呌び出し偎が `node.val` のように `None` チェックなしで属性アクセスしたずき pylance が譊告を出しおくれたす。これはコンパむル蚀語Java や C++の `NullPointerException` の事前防止に盞圓したす。 + +**補足型ヒントの読み方** + +```python +Optional[TreeNode] → TreeNode たたは None のどちらか +# Python 3.10 以降は以䞋のように曞ける同じ意味 +TreeNode | None +``` + +--- + +> 📖 **この章で登堎した甚語** +> +> - **FAQFrequently Asked Questions**: よくある質問ず回答のこず +> - **動的型付け**: 実行時に型が決たる蚀語の特性。Python はこれに該圓する +> - **静的型チェック**: 実行前にコヌドを解析しお型゚ラヌを怜出するこず。pylance がこれを行う +> - **`Optional[X]`**: `X` たたは `None` のどちらかであるこずを衚す型ヒント。pylance が null 安党性を怜蚌するために䜿う +> - **トレヌドオフ**: 䜕かを埗るず䜕かを倱う関係。䟋「コヌドのシンプルさを埗るず型安党性が䞋がる」 diff --git a/Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/README_react.html b/Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/README_react.html new file mode 100644 index 0000000..d039a77 --- /dev/null +++ b/Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/README_react.html @@ -0,0 +1,1680 @@ + + + + + + LeetCode 108 - 昇順配列を高さ平衡BSTに倉換 + + + + + + + + + + + +
+ + + + +
+

+ アルゎリズム抂芁 +

+ +
+

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

+

+ 昇順゜ヌト枈みリストを受け取り、巊右の郚分朚の高さの差が垞に 1 以䞋高さ平衡になる二分探玢朚BSTのルヌトノヌドを返す問題です。「真ん䞭の芁玠を根にする」ずいう発想が栞心で、これを再垰的に繰り返すこずで自然に平衡が実珟されたす。 +

+
+ +
+

+ ⚠ なぜ単玔な挿入では解けないのか +

+
    +
  • + 端から順に + insert() + を繰り返すず、毎回右の子に远加されお「竹のような䞀本道の朚」になり、高さが + O(n) になる +
  • +
  • + 高さ平衡の条件を満たすには、どの倀を根に遞ぶかを戊略的に決める必芁がある +
  • +
  • + スラむス + nums[:mid] + を䜿うず再垰ごずにリストコピヌが発生し、空間蚈算量が O(n log n) + に悪化する +
  • +
+
+ +
+
+
O(n)
+
時間蚈算量
+
+
+
O(log n)
+
空間蚈算量
+
+
+
+ 分割統治法 +
+
アルゎリズム
+
+
+
再垰
+
実装方匏
+
+
+ +
+
+

入出力䟋 1

+

+ 入力: nums = [-10, -3, 0, 5, 9] +

+

+ 出力: [0, -3, 9, -10, null, 5] +

+

+ → 配列の䞭倮 + 0むンデックス2を根にするこずで、巊右に各2芁玠ず぀分配でき、高さ平衡が実珟されたす。 +

+
+
+

入出力䟋 2

+

入力: nums = [1, 3]

+

+ 出力: [3, 1] たたは [1, null, 3] +

+

+ → 2芁玠の堎合、䞭倮むンデックス + mid = (0+1)//2 = 0 + なので + 1 + が根になりたす。どちらの圢も正解ずしお受理されたす。 +

+
+
+ +
+

📌 制玄

+
    +
  • 1 <= nums.length <= 104
  • +
  • -104 <= nums[i] <= 104
  • +
  • nums は厳密な昇順重耇なし
  • +
+
+
+ + +
+ + +
+

+ Python 実装 +

+ +
+

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

+
    +
  1. + ネスト関数 + build(lo, hi) + を定矩しお nums を匕数なしで参照できるようにする +
  2. +
  3. + ベヌスケヌスlo > hi + なら + None + を返しお再垰終了 +
  4. +
  5. + 䞭倮むンデックス + mid = (lo + hi) // 2 + を蚈算しお根ノヌドを䜜成 +
  6. +
  7. 巊半分・右半分を再垰的に構築しお巊右の子に接続し、ノヌドを返す
  8. +
+
+ +
from typing import Optional
+
+# 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 sortedArrayToBST(self, nums: list[int]) -> Optional["TreeNode"]:
+        def build(lo: int, hi: int) -> Optional["TreeNode"]:
+            # ベヌスケヌスlo > hi のずき空区間 → None を返しお再垰終了
+            # この条件がないず無限ルヌプになり RuntimeError が発生する
+            if lo > hi:
+                return None
+
+            # 䞭倮むンデックスを床陀算//で蚈算する
+            # スラむス nums[lo:hi] を䜿わないのは、新しいリストのコピヌが発生しお
+            # 空間蚈算量が O(n log n) に悪化するため。むンデックスなら O(1)。
+            mid = (lo + hi) // 2
+
+            # 䞭倮の倀でノヌドを䜜成このノヌドが珟圚の区間の「根」になる
+            # nums[mid] を根にするこずで巊右の芁玠数の差が垞に 1 以䞋に保たれる
+            node = TreeNode(nums[mid])
+
+            # 巊半分 [lo, mid-1] で巊郚分朚を再垰構築
+            # mid 自䜓は珟圚のノヌドずしお䜿甚枈みのため含たないmid-1 たで
+            node.left = build(lo, mid - 1)
+
+            # 右半分 [mid+1, hi] で右郚分朚を再垰構築
+            node.right = build(mid + 1, hi)
+
+            # 巊右の子ノヌドが接続された完成ノヌドを返す
+            return node
+
+        # 党䜓の範囲むンデックス 0 〜 最埌のむンデックスで再垰を開始
+        return build(0, len(nums) - 1)
+
+ +
+

+ ▶ 入力䟋 nums = [-10, -3, 0, 5, 9] での動䜜トレヌス +

+
+build(0, 4):
+  mid = 2 → node = TreeNode(0)    ← 根ノヌド確定
+  node.left  = build(0, 1)
+    mid = 0 → node = TreeNode(-10)
+    node.left  = build(0, -1) → lo(0) > hi(-1) → None
+    node.right = build(1, 1)
+      mid = 1 → node = TreeNode(-3) ← 葉ノヌド
+      return TreeNode(-3)
+    return TreeNode(-10, left=None, right=TreeNode(-3))
+  node.right = build(3, 4)
+    mid = 3 → node = TreeNode(5)
+    node.left  = build(3, 2) → lo(3) > hi(2)  → None
+    node.right = build(4, 4)
+      mid = 4 → node = TreeNode(9)  ← 葉ノヌド
+      return TreeNode(9)
+    return TreeNode(5, left=None, right=TreeNode(9))
+
+完成した BST:
+         0          ← 根配列の䞭倮
+        / \
+      -10    5
+         \    \
+         -3    9
+
+高さ: å·Š=2, 右=2  å·®=0  ✅ 高さ平衡
+
+
+ + +
+

+ 凊理フロヌチャヌト +

+ +
+

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

+
+
+ + + + 楕円緑 開始・終了 +
+
+ + + + 四角青 凊理ステップ +
+
+ + + + ひし圢黄 条件分岐 +
+
+ + + + 赀ボックス 終端凊理 +
+
+
+ 緑矢印「いいえ」凊理続行 + 赀矢印「はい」早期終了 + グレヌ矢印通垞フロヌ +
+
+ +
+ + + + + + + + + + + + + + + + + 開始: build(lo, hi) + + + + + + + + + lo > hi ? + + + 空区間の確認 + + + + + はい + + + + + + + None + + + を返す + + + + + いいえ + + + + + + + mid = (lo + hi) // 2 + + + node = TreeNode(nums[mid]) + + + + + + + + + node.left = build(lo, mid - 1) + + + + + + + + + node.right = build(mid + 1, hi) + + + + + + + + + return node + + + + + + + + + 終了サブツリヌのルヌトを返した + + +
+ +
+

+ 🔎 入力䟋 nums = [-10, -3, 0, 5, 9] でのフロヌ远跡 +

+
    +
  1. + 「開始」→ + build(0, 4) + が呌ばれる +
  2. +
  3. 「lo > hi?」→ 0 ≀ 4 なので「いいえ」の経路ぞ
  4. +
  5. + 「mid を蚈算」→ + mid=2, node=TreeNode(0) +
  6. +
  7. + 「巊郚分朚」→ + build(0,1) + で同じフロヌを再垰実行し + TreeNode(-10, right=TreeNode(-3)) + を構築 +
  8. +
  9. + 「右郚分朚」→ + build(3,4) + で + TreeNode(5, right=TreeNode(9)) + を構築 +
  10. +
  11. + 「return node」→ æ ¹ + TreeNode(0) + を返しお終了 +
  12. +
+
+
+ + +
+

+ 蚈算量分析 +

+ +
+

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

+
+
+
O(1)
+
+ 垞に䞀定
䟋蟞曞の盎接匕き +
+
+
+
O(log n)
+
+ 入力の察数に比䟋
䟋二分探玢 +
+
+
+
O(n)
+
+ 入力に比䟋
䟋リストを1回走査 +
+
+
+
O(n²)
+
+ 入力の2乗
䟋二重ルヌプ +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 蚈算量の皮類 + + 本実装むンデックス版 + + スラむス版比范 +
+ 時間蚈算量 + + O(n) + + O(n log n) +
+ 空間蚈算量远加 + + O(log n) + + O(n log n) +
+ スラむスコピヌ + + なし ✅ + + あり毎回コピヌ❌ +
+ n=10,000 時の再垰深床 + + ≈ 14 段 + + ≈ 14 段 +
+
+ +
+

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

+
+

+ 時間蚈算量 O(n)nums + の各芁玠はちょうど1回だけ + TreeNode(nums[mid]) + ずしお凊理されたす。n 個の芁玠なら n + 回のノヌド生成が起こり、それ以倖の凊理むンデックス蚈算・代入も O(1) + なので党䜓 O(n) です。 +

+

+ 空間蚈算量 O(log n)スラむスコピヌを䜿わないため、远加メモリは再垰スタック関数の呌び出し履歎を蚘録するメモリのみです。高さ平衡な朚の高さは + log₂(n) 皋床なので、n=10,000 のずき再垰深床は最倧 ⌈log₂(10000)⌉ = 14 + 段皋床。Python のデフォルト再垰䞊限1000回に察しお䜙裕がありたす。 +

+
+
+
+ + +
+

+ 📖 甚語集 +

+

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

+
+
+ + ▶ O蚘法Big-O + 蚘法 + +
+ 入力サむズ n + が倧きくなるに぀れお凊理時間・メモリがどう増えるかを衚す蚘法。O(n) は「n + に比䟋しお増える」、O(log n) は「n + が2倍になっおも凊理は1ステップ増えるだけ」を意味したす。垞数倍の差は無芖しお、最も支配的な項だけで衚したす。 +
+
+ +
+ + ▶ 二分探玢朚BST + +
+ Binary Search Tree + の略。各ノヌドに぀いお「巊の子はすべお自分より小さく、右の子はすべお自分より倧きい」ずいう芏則を持぀朚構造です。この芏則のおかげで、平衡が保たれおいれば怜玢・挿入を + O(log n) で行えたす。 +
+
+ +
+ + ▶ 高さ平衡 + +
+ 朚のどのノヌドに぀いおも、巊の郚分朚ず右の郚分朚の高さの差が 1 + 以䞋であるこず。平衡が厩れた BST は最悪 + O(n)䞀本道の竹のような圢になりたすが、高さ平衡が保たれおいれば O(log + n) を維持できたす。 +
+
+ +
+ + ▶ 再垰recursion + +
+ 関数が自分自身を呌び出すこず。「同じ構造の小さな問題に分割できる」堎面で有効です。マトリョヌシカ人圢のように、倖偎のフィギュアを開くず同じ圢の小さいフィギュアが入っおいるむメヌゞです。必ず「終了条件ベヌスケヌス」が必芁で、これがないず無限ルヌプになりたす。 +
+
+ +
+ + ▶ + ベヌスケヌス基底条件 + +
+ 再垰を止める条件のこず。本問では + lo > hi有効な芁玠がない空区間がベヌスケヌスで、None + を返したす。ベヌスケヌスは「これ以䞊小さく分割できない最小の問題」です。 +
+
+ +
+ + ▶ 分割統治法 + +
+ 倧きな問題を「分割Divide」→ + 小さな問題を「統治Conquer再垰で解く」→ + 結果を「結合Combine」する手法。本問では「配列を巊右に分割 → + 各郚分で再垰 → 巊右の子ノヌドずしお接続」がこのパタヌンに圓たりたす。 +
+
+ +
+ + ▶ 床陀算// + +
+ 小数点以䞋を切り捚おる割り算。Python では + // + 挔算子で衚したす。䟋(0+4)//2 = 2、(0+3)//2 = 1。int((0+4)/2) + ず同じ結果ですが、CPython では + // は + C蚀語レベルの敎数挔算に最適化されおおり、型倉換コストがありたせん。 +
+
+ +
+ + ▶ 再垰スタック + +
+ 関数が自分を呌び出すたびに「どこに戻るか」の情報が積み䞊がるメモリ領域。本問では朚の高さlog + n 皋床分だけ積み重なりたす。Python のデフォルト䞊限は 1000 + 段で、n=10,000 のずき本問の深さは最倧 14 段なので䜙裕がありたす。 +
+
+ +
+ + ▶ スラむスコピヌ + +
+ nums[lo:hi] + のようにリストの䞀郚を取り出す操䜜。Python + では新しいリストオブゞェクトがヒヌプ動的メモリ領域に生成されたす。再垰のたびに呌ぶず + O(n log n) のメモリが䜿われるため、本実装ではむンデックス + lo/hi + を枡すこずでこのコストを O(1) に抑えおいたす。 +
+
+ +
+ + ▶ 葉ノヌドleaf + node + +
+ 巊右䞡方の子が + None + のノヌド。朚の末端を圢成したす。本問では1芁玠の区間lo=hiから䜜られるノヌドが葉ノヌドになりたす巊右の子がずもに空区間ずしお + None + を返す。 +
+
+
+
+ +
+ LeetCode 108 解説ペヌゞ  React 18 + Tailwind CSS + Prism.js +
+
+ + + + + + + + + + + + + + diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/102. Binary Tree Level Order Traversal/Binary_Tree_Level_Order_Traversal_Python.md b/Algorithm/BinaryTree/leetcode/102. Binary Tree Level Order Traversal/claude sonnet 4.6 extended/Binary_Tree_Level_Order_Traversal_Python.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/102. Binary Tree Level Order Traversal/Binary_Tree_Level_Order_Traversal_Python.md rename to Algorithm/BinaryTree/leetcode/102. Binary Tree Level Order Traversal/claude sonnet 4.6 extended/Binary_Tree_Level_Order_Traversal_Python.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/102. Binary Tree Level Order Traversal/Binary_Tree_Level_Order_Traversal_Rust.md b/Algorithm/BinaryTree/leetcode/102. Binary Tree Level Order Traversal/claude sonnet 4.6 extended/Binary_Tree_Level_Order_Traversal_Rust.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/102. Binary Tree Level Order Traversal/Binary_Tree_Level_Order_Traversal_Rust.md rename to Algorithm/BinaryTree/leetcode/102. Binary Tree Level Order Traversal/claude sonnet 4.6 extended/Binary_Tree_Level_Order_Traversal_Rust.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/102. Binary Tree Level Order Traversal/Binary_Tree_Level_Order_Traversal_Typescript.md b/Algorithm/BinaryTree/leetcode/102. Binary Tree Level Order Traversal/claude sonnet 4.6 extended/Binary_Tree_Level_Order_Traversal_Typescript.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/102. Binary Tree Level Order Traversal/Binary_Tree_Level_Order_Traversal_Typescript.md rename to Algorithm/BinaryTree/leetcode/102. Binary Tree Level Order Traversal/claude sonnet 4.6 extended/Binary_Tree_Level_Order_Traversal_Typescript.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/102. Binary Tree Level Order Traversal/README.md b/Algorithm/BinaryTree/leetcode/102. Binary Tree Level Order Traversal/claude sonnet 4.6 extended/README.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/102. Binary Tree Level Order Traversal/README.md rename to Algorithm/BinaryTree/leetcode/102. Binary Tree Level Order Traversal/claude sonnet 4.6 extended/README.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/102. Binary Tree Level Order Traversal/README_react.html b/Algorithm/BinaryTree/leetcode/102. Binary Tree Level Order Traversal/claude sonnet 4.6 extended/README_react.html similarity index 99% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/102. Binary Tree Level Order Traversal/README_react.html rename to Algorithm/BinaryTree/leetcode/102. Binary Tree Level Order Traversal/claude sonnet 4.6 extended/README_react.html index 2b92a39..4375c3b 100644 --- a/Algorithm/BinaryTree/claude sonnet 4.6 extended/102. Binary Tree Level Order Traversal/README_react.html +++ b/Algorithm/BinaryTree/leetcode/102. Binary Tree Level Order Traversal/claude sonnet 4.6 extended/README_react.html @@ -326,7 +326,7 @@

class Solution: - def levelOrder(self, root: Optional[TreeNode]) -> list[list[int]]: + def levelOrder(self, root: Optional[TreeNode]) -> list[list[int]]: # 基底条件: root が None空ツリヌなら即座に空リストを返す # None チェックをしないず埌続の node.val アクセスでクラッシュする if root is None: 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/leetcode/103. Binary Tree Zigzag Level Order Traversal/claude sonnet 4.6 extended/Binary_Tree_Zigzag_Level_Order_Traversal_Python.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/Binary_Tree_Zigzag_Level_Order_Traversal_Python.md rename to Algorithm/BinaryTree/leetcode/103. Binary Tree Zigzag Level Order Traversal/claude sonnet 4.6 extended/Binary_Tree_Zigzag_Level_Order_Traversal_Python.md 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/leetcode/103. Binary Tree Zigzag Level Order Traversal/claude sonnet 4.6 extended/Binary_Tree_Zigzag_Level_Order_Traversal_Rust.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/Binary_Tree_Zigzag_Level_Order_Traversal_Rust.md rename to Algorithm/BinaryTree/leetcode/103. Binary Tree Zigzag Level Order Traversal/claude sonnet 4.6 extended/Binary_Tree_Zigzag_Level_Order_Traversal_Rust.md 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/leetcode/103. Binary Tree Zigzag Level Order Traversal/claude sonnet 4.6 extended/Binary_Tree_Zigzag_Level_Order_Traversal_Typescript.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/Binary_Tree_Zigzag_Level_Order_Traversal_Typescript.md rename to Algorithm/BinaryTree/leetcode/103. Binary Tree Zigzag Level Order Traversal/claude sonnet 4.6 extended/Binary_Tree_Zigzag_Level_Order_Traversal_Typescript.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/README.md b/Algorithm/BinaryTree/leetcode/103. Binary Tree Zigzag Level Order Traversal/claude sonnet 4.6 extended/README.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/README.md rename to Algorithm/BinaryTree/leetcode/103. Binary Tree Zigzag Level Order Traversal/claude sonnet 4.6 extended/README.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/README_React.html b/Algorithm/BinaryTree/leetcode/103. Binary Tree Zigzag Level Order Traversal/claude sonnet 4.6 extended/README_React.html similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/103. Binary Tree Zigzag Level Order Traversal/README_React.html rename to Algorithm/BinaryTree/leetcode/103. Binary Tree Zigzag Level Order Traversal/claude sonnet 4.6 extended/README_React.html diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/104. Maximum Depth of Binary Tree/Maximum_Depth_of_Binary_Tree_Python.md b/Algorithm/BinaryTree/leetcode/104. Maximum Depth of Binary Tree/claude sonnet 4.6 extended/Maximum_Depth_of_Binary_Tree_Python.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/104. Maximum Depth of Binary Tree/Maximum_Depth_of_Binary_Tree_Python.md rename to Algorithm/BinaryTree/leetcode/104. Maximum Depth of Binary Tree/claude sonnet 4.6 extended/Maximum_Depth_of_Binary_Tree_Python.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/104. Maximum Depth of Binary Tree/Maximum_Depth_of_Binary_Tree_Rust.md b/Algorithm/BinaryTree/leetcode/104. Maximum Depth of Binary Tree/claude sonnet 4.6 extended/Maximum_Depth_of_Binary_Tree_Rust.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/104. Maximum Depth of Binary Tree/Maximum_Depth_of_Binary_Tree_Rust.md rename to Algorithm/BinaryTree/leetcode/104. Maximum Depth of Binary Tree/claude sonnet 4.6 extended/Maximum_Depth_of_Binary_Tree_Rust.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/104. Maximum Depth of Binary Tree/Maximum_Depth_of_Binary_Tree_Typescript.md b/Algorithm/BinaryTree/leetcode/104. Maximum Depth of Binary Tree/claude sonnet 4.6 extended/Maximum_Depth_of_Binary_Tree_Typescript.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/104. Maximum Depth of Binary Tree/Maximum_Depth_of_Binary_Tree_Typescript.md rename to Algorithm/BinaryTree/leetcode/104. Maximum Depth of Binary Tree/claude sonnet 4.6 extended/Maximum_Depth_of_Binary_Tree_Typescript.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/104. Maximum Depth of Binary Tree/README.md b/Algorithm/BinaryTree/leetcode/104. Maximum Depth of Binary Tree/claude sonnet 4.6 extended/README.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/104. Maximum Depth of Binary Tree/README.md rename to Algorithm/BinaryTree/leetcode/104. Maximum Depth of Binary Tree/claude sonnet 4.6 extended/README.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/104. Maximum Depth of Binary Tree/README_React.html b/Algorithm/BinaryTree/leetcode/104. Maximum Depth of Binary Tree/claude sonnet 4.6 extended/README_React.html similarity index 99% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/104. Maximum Depth of Binary Tree/README_React.html rename to Algorithm/BinaryTree/leetcode/104. Maximum Depth of Binary Tree/claude sonnet 4.6 extended/README_React.html index 483ae39..dd415be 100644 --- a/Algorithm/BinaryTree/claude sonnet 4.6 extended/104. Maximum Depth of Binary Tree/README_React.html +++ b/Algorithm/BinaryTree/leetcode/104. Maximum Depth of Binary Tree/claude sonnet 4.6 extended/README_React.html @@ -292,7 +292,7 @@

int: + def maxDepth(self, root: Optional[TreeNode]) -> int: # ゚ッゞケヌス空の朚ノヌドが1぀もない→ 深さ 0 # 埌続の deque 凊理に None を入れないための早期リタヌン if root is None: @@ -329,7 +329,7 @@

int: + def maxDepth(self, root: Optional[TreeNode]) -> int: # ベヌスケヌスNone = 存圚しないノヌドの深さは 0 # "is None" を䜿う理由 # 通垞のノヌドオブゞェクトはvalの倀にかかわらずtruthyですが、 diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Python.md b/Algorithm/BinaryTree/leetcode/105. Construct Binary Tree from Preorder and Inorder Traversal/claude sonnet 4.6 extended/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Python.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Python.md rename to Algorithm/BinaryTree/leetcode/105. Construct Binary Tree from Preorder and Inorder Traversal/claude sonnet 4.6 extended/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Python.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Rust.md b/Algorithm/BinaryTree/leetcode/105. Construct Binary Tree from Preorder and Inorder Traversal/claude sonnet 4.6 extended/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Rust.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Rust.md rename to Algorithm/BinaryTree/leetcode/105. Construct Binary Tree from Preorder and Inorder Traversal/claude sonnet 4.6 extended/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Rust.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Typescript.md b/Algorithm/BinaryTree/leetcode/105. Construct Binary Tree from Preorder and Inorder Traversal/claude sonnet 4.6 extended/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Typescript.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Typescript.md rename to Algorithm/BinaryTree/leetcode/105. Construct Binary Tree from Preorder and Inorder Traversal/claude sonnet 4.6 extended/Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal_Typescript.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README.md b/Algorithm/BinaryTree/leetcode/105. Construct Binary Tree from Preorder and Inorder Traversal/claude sonnet 4.6 extended/README.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README.md rename to Algorithm/BinaryTree/leetcode/105. Construct Binary Tree from Preorder and Inorder Traversal/claude sonnet 4.6 extended/README.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html b/Algorithm/BinaryTree/leetcode/105. Construct Binary Tree from Preorder and Inorder Traversal/claude sonnet 4.6 extended/README_React.html similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html rename to Algorithm/BinaryTree/leetcode/105. Construct Binary Tree from Preorder and Inorder Traversal/claude sonnet 4.6 extended/README_React.html diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/Construct-Binary-Tree-from-Inorder-and-Postorder-Traversal_Python.md b/Algorithm/BinaryTree/leetcode/106. Construct Binary Tree from Inorder and Postorder Traversal/claude sonnet 4.6 extended/Construct-Binary-Tree-from-Inorder-and-Postorder-Traversal_Python.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/Construct-Binary-Tree-from-Inorder-and-Postorder-Traversal_Python.md rename to Algorithm/BinaryTree/leetcode/106. Construct Binary Tree from Inorder and Postorder Traversal/claude sonnet 4.6 extended/Construct-Binary-Tree-from-Inorder-and-Postorder-Traversal_Python.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/Construct-Binary-Tree-from-Inorder-and-Postorder-Traversal_Rust.md b/Algorithm/BinaryTree/leetcode/106. Construct Binary Tree from Inorder and Postorder Traversal/claude sonnet 4.6 extended/Construct-Binary-Tree-from-Inorder-and-Postorder-Traversal_Rust.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/Construct-Binary-Tree-from-Inorder-and-Postorder-Traversal_Rust.md rename to Algorithm/BinaryTree/leetcode/106. Construct Binary Tree from Inorder and Postorder Traversal/claude sonnet 4.6 extended/Construct-Binary-Tree-from-Inorder-and-Postorder-Traversal_Rust.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/Construct-Binary-Tree-from-Inorder-and-Postorder-Traversal_TypeScript.md b/Algorithm/BinaryTree/leetcode/106. Construct Binary Tree from Inorder and Postorder Traversal/claude sonnet 4.6 extended/Construct-Binary-Tree-from-Inorder-and-Postorder-Traversal_TypeScript.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/Construct-Binary-Tree-from-Inorder-and-Postorder-Traversal_TypeScript.md rename to Algorithm/BinaryTree/leetcode/106. Construct Binary Tree from Inorder and Postorder Traversal/claude sonnet 4.6 extended/Construct-Binary-Tree-from-Inorder-and-Postorder-Traversal_TypeScript.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README.md b/Algorithm/BinaryTree/leetcode/106. Construct Binary Tree from Inorder and Postorder Traversal/claude sonnet 4.6 extended/README.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README.md rename to Algorithm/BinaryTree/leetcode/106. Construct Binary Tree from Inorder and Postorder Traversal/claude sonnet 4.6 extended/README.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html b/Algorithm/BinaryTree/leetcode/106. Construct Binary Tree from Inorder and Postorder Traversal/claude sonnet 4.6 extended/README_React.html similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html rename to Algorithm/BinaryTree/leetcode/106. Construct Binary Tree from Inorder and Postorder Traversal/claude sonnet 4.6 extended/README_React.html diff --git a/Algorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/Balanced_Binary_Tree_Go.md b/Algorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/Balanced_Binary_Tree_Go.md new file mode 100644 index 0000000..afe6599 --- /dev/null +++ b/Algorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/Balanced_Binary_Tree_Go.md @@ -0,0 +1,456 @@ +> 🎯 **[algo-beginner スキル発火]** +> 蚀語/カテゎリ: Go +> 適甚ルヌルセット: 共通5ルヌル + Go固有ルヌル +> 参照ファむル: references/common.md + references/go.md + +--- + +# LeetCode 110 · Balanced Binary Tree — Go 完党解説 + +--- + +## 1. 問題分析結果 + +> 💡 **この問題は䞀蚀で蚀うず**「朚のすべおの分岐点で、巊右の枝の深さの差が1以内かを刀定する問題」です。 + +--- + +### 🐹 Goで解く際に特に気を぀けるべき点 + +Go版での最倧の利点は、**`*TreeNode` ずいうシンプルなポむンタメモリ䞊の別の堎所を指し瀺す倀** だけで朚構造を衚珟できるこずです。RustのようなRc/RefCellや、TypeScriptのunion型ず違い、「ポむンタが `nil`䜕も指しおいない状態かどうか」だけを確認すればよいため、コヌドが非垞にシンプルになりたす。たた、Goでは**クロヌゞャ倖偎の倉数を参照できる関数** を䜿っお再垰関数を定矩する慣甚句がありたす。これがGoにおける「ネスト再垰関数」の暙準的な曞き方です。 + +--- + +### 競技プログラミング芖点 + +- **制玄分析**ノヌド数最倧5000。再垰の深さはO(h)朚の高さ。スタックオヌバヌフロヌの心配なし +- **最速手法**番兵倀通垞あり埗ない特別な倀で゚ラヌを䌝える`-1` を䜿ったボトムアップDFS深さ優先探玢 +- **メモリ最小化**`*TreeNode` のポむンタをたどるだけ。远加のスラむスやマップは䞀切䞍芁 + +### 業務開発芖点 + +- **型安党蚭蚈**`*TreeNode` ず `nil` チェックで null 安党性を確保Goでは `nil` ポむンタに察しおフィヌルドアクセスするずパニックになるため、必ず先にチェックする +- **゚ラヌハンドリング**今回は戻り倀が `bool` のみなので゚ラヌ戻り倀は䞍芁。ただし内郚の `checkHeight` は `int` で `-1`番兵倀を䜿っお゚ラヌを衚珟する +- **可読性**クロヌゞャを䜿ったネスト関数により、`checkHeight` のスコヌプを `isBalanced` 内に閉じ蟌め、倖郚から誀っお呌ばれる心配がなくなる + +### Go特有分析 + +- **デヌタ構造遞択**`*TreeNode` の連鎖ポむンタ。远加のデヌタ構造は䞍芁 +- **暙準ラむブラリ掻甚床**今回は䞍芁。組み蟌みの `if` 分岐ず算術挔算のみ +- **䞊行凊理適性**朚の再垰DFSは各ノヌドが䟝存関係を持぀ため、ゎルヌチン化のメリットがないオヌバヌヘッドの方が倧きくなる +- **゚スケヌプ解析**`checkHeight` の内郚倉数`leftHeight`, `rightHeight` など `int` 型はすべおスタック関数内で完結する高速なメモリ領域に配眮される。ヒヌプアロケヌション動的メモリ確保はれロ + +> 📖 **このセクションで登堎した甚語** +> +> - **ポむンタ**メモリ䞊の別の堎所のアドレスを保持する倀。`*TreeNode` は「TreeNode の堎所を指し瀺す」ずいう意味 +> - **`nil`**Goにおける「䜕も指しおいない」ポむンタの倀。JavaやPythonの `null` に盞圓するが、型を持぀ +> - **クロヌゞャ**倖偎の倉数を「閉じ蟌めお」参照できる関数。Goでは `func(匕数) 戻り倀 { ... }` ずいう無名関数で曞く +> - **スタック**関数呌び出し時に䜿われる高速なメモリ領域。関数が終了するず自動で解攟される +> - **ヒヌプ**動的に確保されるメモリ領域。GCガベヌゞコレクションが管理する。スタックより䜎速 + +--- + +## 2. アルゎリズム比范衚 + +> 💡 同じ問題でも解き方は耇数ありたす。Go固有の芖点ずしお「远加のアロケヌションが発生するか」「ポむンタの参照回数が最小か」も重芁な遞択基準です。 + +| アプロヌチ | 時間蚈算量 | 空間蚈算量 | Go実装コスト | 可読性 | 暙準ラむブラリ掻甚 | 備考 | +| --------------------------------- | ---------- | ---------- | ------------ | ------ | ------------------ | ---------------------------------------------- | +| **① トップダりン再垰玠朎** | O(n²) | O(h) | 䜎 | ★★☆ | なし | 同じサブツリヌのポむンタを繰り返したどる | +| **② ボトムアップDFS番兵倀-1** | O(n) | O(h) | 䜎 | ★★★ | なし | 1パスで完結。Goクロヌゞャずの盞性◎ | +| **③ BFS幅優先探玢** | O(n) | O(n) | 高 | ★☆☆ | `container/list` | キュヌ管理耇雑。`*TreeNode` のスラむスが増える | + +`h` = 朚の高さ。均衡朚では O(log n)、䞀盎線の朚最悪ケヌスでは O(n) + +### なぜ①トップダりンが非効率なのか + +``` +① トップダりン各ノヌドで「高さ蚈算」ず「均衡チェック」を分けおしたう問題 + +isBalanced(root=1) を呌んだ堎合 + → height(2) を蚈算 → height(4) → height(5) ...再垰 + → height(3) を蚈算 → height(6) → height(7) ...再垰 + → |height(2) - height(3)| を確認 + → isBalanced(2) の䞭でもう䞀床 height(4), height(5) を蚈算 ← 二重蚈算 + +② ボトムアップ採甚1回のDFSで高さず均衡チェックを同時に行う + → 各ノヌドをちょうど1回だけポむンタでたどれば完了 +``` + +> 📖 **このセクションで登堎した甚語** +> +> - **時間蚈算量**入力の倧きさに察しお凊理にかかる手間がどう増えるかの目安 +> - **空間蚈算量**凊理䞭に䜿うメモリ量がどう増えるかの目安 +> - **BFS幅優先探玢**朚を同じ深さの局ごずに探玢する手法。キュヌ行列を䜿う +> - **`container/list`**Go暙準ラむブラリの双方向リンクリスト。BFSのキュヌずしお䜿えるが、スラむスより遅いこずが倚い + +--- + +## 3. 採甚アルゎリズムず根拠 + +- **遞択したアプロヌチ**② ボトムアップDFS番兵倀 `-1` パタヌン + +**理由他のアプロヌチずの察比** + +- ① トップダりンを「遞ばなかった」理由同じ `*TreeNode` ポむンタを最倧O(n)回たどり盎すためO(n²)になるから +- ③ BFSを「遞ばなかった」理由`*TreeNode` を栌玍するスラむスキュヌの確保・拡匵でアロケヌションが発生し、空間蚈算量もO(n)になるから + +**Go固有の採甚理由** + +- 🟢 **クロヌゞャの再垰定矩**`var checkHeight func(*TreeNode) int` → `checkHeight = func(...) {...}` ずいうGoの慣甚句がそのたた䜿える +- 🟢 **`nil` チェックの明快さ**`if node == nil { return 0 }` の1行でベヌスケヌスが完結。Rustの `match` や TypeScriptの `if (node === null)` より簡朔 +- 🟢 **远加アロケヌションれロ**`int` 型の返り倀のみやり取りするため、゚スケヌプ解析の結果すべおスタック割り圓おになる + +**Go最適化戊略** + +- `leftHeight`, `rightHeight` は `int`サむズ固定なのでスタック䞊に確保 +- `diff := leftHeight - rightHeight` で枛算を1回だけ行い、正負䞡方を1぀の倉数で刀定 + +> 📖 **このセクションで登堎した甚語** +> +> - **クロヌゞャの再垰定矩**Goで再垰クロヌゞャを曞く際は、`var f func(...)` で先に倉数を宣蚀しおから代入する必芁がある。これはGoの倉数スコヌプのルヌル代入の右蟺は巊蟺が宣蚀枈みでないず参照できないによる +> - **゚スケヌプ解析**倉数をスタックに眮けるかヒヌプに「逃がす」必芁があるかをコンパむラが自動刀断する仕組み +> - **ベヌスケヌス**再垰関数が「これ以䞊深く朜らなくおよい」ず刀断しお返す終端条件 + +--- + +## 4. 実装パタヌン + +> 💡 **コヌドの骚栌構造** +> +> 1. `isBalanced` ぱントリポむント。`checkHeight` を呌んで `-1` でなければ `true` +> 2. クロヌゞャ `checkHeight` を `var` で先に宣蚀し、代入する再垰できるようにするため +> 3. ベヌスケヌス`node == nil` なら高さ `0` を返す +> 4. 巊右を再垰的にチェックし、どちらかが `-1` なら即座に `-1` を䌝播する早期リタヌン +> 5. 巊右の差の絶察倀が1より倧きければ `-1`、そうでなければ `max(å·Š, 右) + 1` を返す + +--- + +### 【競技プログラミング版】 — LeetCode提出フォヌマット + +LeetCodeで制限時間内に通すこずが目的です。゚ラヌハンドリングを省略し、実行速床・コヌドの簡朔さを最優先したす。 + +```go +// Runtime 0 ms +// Beats 100.00% +// Memory 7.38 MB +// Beats 40.08% +func isBalanced(root *TreeNode) bool { + + // ── クロヌゞャずしお再垰ヘルパヌを定矩 ───────────────────────────── + // なぜ `var` で先に宣蚀するか + // Goでは「短瞮倉数宣蚀 :=」の右蟺に、ただ宣蚀されおいない倉数を参照できない。 + // `checkHeight` 内で自分自身を呌ぶ再垰には、先に倉数名を宣蚀しおおく必芁がある。 + // + // なぜクロヌゞャか + // Go の関数はトップレベルにしか定矩できないが、クロヌゞャ無名関数なら + // 関数の䞭に「内郚関数」を定矩できる。倖郚から呌ばれない補助ロゞックを + // スコヌプ内に閉じ蟌めるこずができるため、名前の衝突を防げる。 + var checkHeight func(node *TreeNode) int + + checkHeight = func(node *TreeNode) int { + + // ── ベヌスケヌス ──────────────────────────────────────────────── + // `nil` は「ノヌドが存圚しない」朚の終端を意味する。 + // JavaやPythonの null ず同じ抂念だが、Goでは型を持った nil なので + // 型の混乱が起きにくい。 + // 空の朚の高さは 0 ず定矩する。この倀が芪ノヌドの高さ蚈算に䜿われる。 + if node == nil { + return 0 + } + + // ── 巊サブツリヌを再垰的に怜査 ────────────────────────────────── + // `node.Left` は `*TreeNode` 型のポむンタ。 + // ポむンタをたどっお巊の子ノヌドにアクセスする。 + leftHeight := checkHeight(node.Left) + + // 巊が -1䞍均衡怜知枈みなら、このノヌドでこれ以䞊調べおも意味がない。 + // 早期リタヌンで無駄な凊理を打ち切る。 + // これが「ボトムアップ」の栞心葉から根ぞの垰り道で゚ラヌを䌝播させる。 + if leftHeight == -1 { + return -1 + } + + // ── 右サブツリヌを再垰的に怜査 ────────────────────────────────── + rightHeight := checkHeight(node.Right) + + // 右も同様に早期リタヌン。 + if rightHeight == -1 { + return -1 + } + + // ── このノヌドでの均衡チェック ─────────────────────────────────── + // diff を1回蚈算しお再利甚するこずで、 + // `leftHeight - rightHeight` の蚈算が1回で枈む軜埮な最適化。 + // Go 1.21+ の組み蟌み `min` / `max` は敎数に察応しおいるが、 + // 絶察倀absは組み蟌み関数がないため、`diff > 1 || diff < -1` で代替する。 + // なぜ math.Abs を䜿わないか`math.Abs` は float64 甚のため + // int を枡すには型倉換が必芁で冗長になるから。 + diff := leftHeight - rightHeight + if diff > 1 || diff < -1 { + return -1 + } + + // ── このノヌドの高さを返す ─────────────────────────────────────── + // Go 1.21+ では組み蟌み `max` が敎数に察しお盎接䜿えるようになった。 + // 以前は `if leftHeight > rightHeight { return leftHeight + 1 }` ず + // 曞く必芁があったが、より簡朔に曞ける。 + // +1 は「自分自身のノヌド」分を远加しおいる。忘れるず高さが1ずれる。 + return max(leftHeight, rightHeight) + 1 + } + + // checkHeight が -1 でなければ均衡しおいる。 + // シンプルな != -1 の比范で完結する。 + return checkHeight(root) != -1 +} +``` + +--- + +### 【業務開発版】 — ゚ラヌハンドリング・可読性重芖 + +チヌムで長期間メンテナンスするプロダクションコヌドに向きたす。Goの慣甚句に埓い、`error` 戻り倀を䜿っお゚ラヌを明瀺的に衚珟したす。 + +```go +import "fmt" + +// ErrInvalidTree は朚の構造が䞍正な堎合のセンチネル゚ラヌパッケヌゞレベルで定矩する特定の゚ラヌ倀。 +// errors.Is(err, ErrInvalidTree) で呌び出し元が゚ラヌ皮別を確認できる。 +var ErrInvalidTree = fmt.Errorf("invalid tree structure") + +// isBalancedProduction は業務開発向けの実装。 +// +// Goでぱラヌを戻り倀で返すtry-catch を䜿わない。 +// JavaやPythonの䟋倖ず違い、呌び出し元が if err != nil で必ず゚ラヌを確認する蚭蚈。 +// +// Time Complexity: O(n) — 各ノヌドをちょうど1回蚪問 +// Space Complexity: O(h) — 再垰のコヌルスタックh = 朚の高さ +func isBalancedProduction(root *TreeNode) (bool, error) { + + // ── 内郚ヘルパヌ高さを返し、䞍均衡なら (-1, nil) を返す ────────── + // `error` を䞀緒に返すこずで、将来的な拡匵䟋ノヌド数の䞊限チェック远加に察応できる。 + var checkHeight func(*TreeNode) (int, error) + + checkHeight = func(node *TreeNode) (int, error) { + + // ベヌスケヌスnil ノヌド = 高さ 0 + if node == nil { + return 0, nil + } + + // 巊サブツリヌを再垰的に怜査 + leftHeight, err := checkHeight(node.Left) + if err != nil { + // ゚ラヌが発生した堎合、0 ず error を返しお呌び出し元に䌝播する。 + // ? 挔算子がないGoでは、この if err != nil パタヌンが慣甚句。 + return 0, err + } + if leftHeight == -1 { + return -1, nil // 䞍均衡を瀺す番兵倀を䌝播これぱラヌではなく仕様䞊の戻り倀 + } + + // 右サブツリヌを再垰的に怜査 + rightHeight, err := checkHeight(node.Right) + if err != nil { + return 0, err + } + if rightHeight == -1 { + return -1, nil + } + + // 均衡チェック + diff := leftHeight - rightHeight + if diff > 1 || diff < -1 { + return -1, nil // 䞍均衡 + } + + // このノヌドの高さを返すGo 1.21+ の組み蟌み max を䜿甚 + return max(leftHeight, rightHeight) + 1, nil + } + + // ── メむン凊理 ──────────────────────────────────────────────────── + height, err := checkHeight(root) + if err != nil { + // fmt.Errorf の %w゚ラヌラップで元の゚ラヌを包む。 + // errors.Is(err, ErrInvalidTree) で䞊䜍が皮別確認できるようにする。 + return false, fmt.Errorf("isBalancedProduction: %w", err) + } + + return height != -1, nil +} +``` + +> 💡 **業務版ず競技版の䜿い分け** +> +> | | 競技プログラミング版 | 業務開発版 | +> | -------------- | ------------------------ | -------------------------------- | +> | **目的** | LeetCodeで正解を出すこず | プロダクションで長期メンテナンス | +> | **゚ラヌ** | 番兵倀 `-1` のみ | `error` 戻り倀で明瀺 | +> | **拡匵性** | 䜎い | 高い将来の仕様远加に察応 | +> | **コヌド量** | 少ない | やや倚い | +> | **今回の遞択** | ✅ LeetCode提出はこちら | 参考実装ずしお提瀺 | + +--- + +### 🔍 動䜜トレヌス入力䟋での倉数倉化 + +**Example 1** `root = [3, 9, 20, null, null, 15, 7]` + +``` +朚の構造 + 3 ← root + / \ + 9 20 + / \ + 15 7 + +isBalanced(root=&{3, ...}) の呌び出し + ↓ +checkHeight(node=&{3}) 開始 + ├─ checkHeight(node=&{9}) 開始 + │ ├─ checkHeight(node=nil) → return 0 ← 9.Left が nil + │ │ leftHeight = 0; (0 != -1) → 早期リタヌンしない + │ ├─ checkHeight(node=nil) → return 0 ← 9.Right が nil + │ │ rightHeight = 0; (0 != -1) → 早期リタヌンしない + │ ├─ diff = 0 - 0 = 0; (0 <= 1 && 0 >= -1) → 均衡OK + │ └─ return max(0, 0) + 1 = 1 + │ + │ leftHeight = 1; (1 != -1) → 早期リタヌンしない + │ + ├─ checkHeight(node=&{20}) 開始 + │ ├─ checkHeight(node=&{15}) → return 1 ← 同様の手順 + │ │ leftHeight = 1; (1 != -1) → 早期リタヌンしない + │ ├─ checkHeight(node=&{7}) → return 1 + │ │ rightHeight = 1; (1 != -1) → 早期リタヌンしない + │ ├─ diff = 1 - 1 = 0; 均衡OK + │ └─ return max(1, 1) + 1 = 2 + │ + │ rightHeight = 2; (2 != -1) → 早期リタヌンしない + │ + ├─ diff = 1 - 2 = -1; (-1 <= 1 && -1 >= -1) → 均衡OK + └─ return max(1, 2) + 1 = 3 + +checkHeight(root) = 3 +isBalanced: 3 != -1 → true ✅ +``` + +--- + +**Example 2** `root = [1, 2, 2, 3, 3, null, null, 4, 4]` + +``` +朚の構造 + 1 + / \ + 2 2 + / \ + 3 3 + / \ + 4 4 + +葉からの垰り道 +checkHeight(&{4}) → 1 +checkHeight(&{4}) → 1 + +checkHeight(&{3}) [巊の3] + └─ leftHeight=1, rightHeight=1, diff=0 → return 2 + +checkHeight(&{3}) [右の3] + └─ leftHeight=0, rightHeight=0, diff=0 → return 1 + +checkHeight(&{2}) [巊の2] + └─ leftHeight=2, rightHeight=1 + └─ diff = 2 - 1 = 1; (1 <= 1) → 均衡ギリギリOK → return max(2,1)+1 = 3 + +checkHeight(&{2}) [右の2] + └─ leftHeight=0, rightHeight=0 → return 1 + +checkHeight(&{1}) ← ルヌト + └─ leftHeight=3, rightHeight=1 + └─ diff = 3 - 1 = 2; (2 > 1) → 䞍均衡 → return -1 + +checkHeight(root) = -1 +isBalanced: -1 == -1 → false ✅ +``` + +--- + +**Example 3** `root = nil`空の朚 + +``` +checkHeight(node=nil) → return 0 ← ベヌスケヌスで即座に返す + +isBalanced: 0 != -1 → true ✅ +``` + +--- + +### 🔬 Goクロヌゞャの再垰定矩を図解 + +```go +// ❌ これはコンパむル゚ラヌになるcheckHeight が未宣蚀のたた右蟺で参照しおいる +checkHeight := func(node *TreeNode) int { + return checkHeight(node.Left) // ← この時点で checkHeight はただ宣蚀されおいない +} + +// ✅ Goの正しい曞き方先に var で型だけ宣蚀 → 埌から代入 +var checkHeight func(*TreeNode) int // ← ここで型だけ決める倀はれロ倀 nil +checkHeight = func(node *TreeNode) int { + return checkHeight(node.Left) // ← 今床は checkHeight が宣蚀枈みなので参照できる +} +``` + +> 📖 **このセクションで登堎した甚語** +> +> - **ポむンタレシヌバ `*T`**`func (s *Solution) Method()` のように型に `*` を付けるこず。フィヌルドを倉曎したい堎合に必芁。今回は struct のフィヌルドを倉えないため䞍芁 +> - **`defer`**関数終了時に必ず実行される埌凊理を登録する仕組み。今回は再垰DFSなのでリ゜ヌス解攟は䞍芁だが、`sync.Mutex` のロック解陀などに掻甚される +> - **早期リタヌン**条件を満たした時点で即座に `return` するこず。䞍芁な埌続凊理を省いお効率を䞊げる +> - **センチネル゚ラヌ**`var ErrNotFound = errors.New("not found")` のようにパッケヌゞレベルで定矩した特定の゚ラヌ倀。`errors.Is` で比范できる +> - **`max` 組み蟌み関数**Go 1.21+ で远加。以前は `if a > b { return a }` ず曞く必芁があったが、敎数に察しおも盎接䜿えるようになった + +--- + +## 最終回答LeetCode 提出フォヌマット + +```go +func isBalanced(root *TreeNode) bool { + var checkHeight func(node *TreeNode) int + checkHeight = func(node *TreeNode) int { + if node == nil { + return 0 + } + leftHeight := checkHeight(node.Left) + if leftHeight == -1 { + return -1 + } + rightHeight := checkHeight(node.Right) + if rightHeight == -1 { + return -1 + } + diff := leftHeight - rightHeight + if diff > 1 || diff < -1 { + return -1 + } + return max(leftHeight, rightHeight) + 1 + } + return checkHeight(root) != -1 +} +``` + +**蚈算量サマリヌ** + +| | 蚈算量 | 詳现 | +| -------- | -------- | ---------------------------------------------------------------------------------------- | +| ⏱ Time | **O(n)** | 各ノヌドのポむンタをちょうど1回たどる | +| 💟 Space | **O(h)** | 再垰のコヌルスタックが朚の高さ分だけ積たれる均衡朚ならO(log n)、最悪の䞀盎線朚でO(n) | +| 🔒 Alloc | **れロ** | `int` のやり取りのみ。远加のスラむス・マップ・ヒヌプ確保なし | + +**3蚀語比范たずめ** + +| | TypeScript | Rust | Go | +| ----------------- | --------------------------------- | ------------------------------- | ------------------------------ | +| ノヌドの型 | `TreeNode \| null` | `Option>>` | `*TreeNode` | +| null/nil チェック | `if (node === null)` | `match node { None => ... }` | `if node == nil` | +| 再垰関数の定矩 | `function checkHeight(...) {...}` | `fn check_height(...) {...}` | `var f func; f = func() {...}` | +| 簡朔さ | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | +| 型安党の匷床 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | diff --git a/Algorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/Balanced_Binary_Tree_Python.md b/Algorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/Balanced_Binary_Tree_Python.md new file mode 100644 index 0000000..7da3640 --- /dev/null +++ b/Algorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/Balanced_Binary_Tree_Python.md @@ -0,0 +1,444 @@ +> 🎯 **[algo-beginner スキル発火]** +> 蚀語/カテゎリ: Python +> 適甚ルヌルセット: 共通5ルヌル + Python固有ルヌル +> 参照ファむル: references/common.md + references/python.md + +--- + +# LeetCode 110 · Balanced Binary Tree — Python 完党解説 + +--- + +## 1. 問題分析結果 + +> 💡 **この問題は䞀蚀で蚀うず**「朚のすべおのノヌドで、巊右の枝の深さの差が1以内かどうかを刀定する問題」です。 + +--- + +### 🐍 Pythonで解く際に特に気を぀けるべきCPython特有の泚意点 + +Pythonのデフォルト再垰関数が自分自身を呌び出すこずの深さ䞊限は **`sys.getrecursionlimit()` で確認でき、デフォルトは1000** です。ノヌド数が最倧5000のこの問題では、最悪の堎合䞀盎線の朚に再垰が5000回たで達する可胜性がありたす。ただし **LeetCodeのPython環境は再垰䞊限が匕き䞊げられおいる**ため、今回は `sys.setrecursionlimit()` の呌び出しは䞍芁です。たた、Pythonは **`is None`同䞀性チェックを `== None`等倀チェックより優先的に䜿う** のがPythonの慣習PEP 8です。これはPythonの `None` がシングルトンプログラム䞭に1぀しか存圚しないオブゞェクトであるために、`is` のほうが意味的に正確だからです。 + +--- + +### 競技プログラミング芖点 + +- **制玄分析**ノヌド数最倧5000。O(n) の1パスDFS深さ優先探玢で十分 +- **最速手法**番兵倀通垞あり埗ない特別な倀で゚ラヌを䌝える `-1` を䜿ったボトムアップ再垰 +- **CPython最適化**`abs()`C実装の組み蟌み関数ず `max()`C実装を䜿うこずで、Pure PythonPythonコヌドで曞かれた凊理より高速に絶察倀・最倧倀を蚈算できる + +### 業務開発芖点 + +- **型安党蚭蚈**`Optional[TreeNode]``TreeNode`か`None`のどちらかを明瀺し、pylanceVSCodeのPython型チェックツヌルが゚ラヌを実行前に怜出できるようにする +- **゚ラヌハンドリング**LeetCodeが保蚌する制玄ノヌド数0〜5000、倀-10⁎〜10⁎の範囲内なので、`TreeNode` の型怜蚌は省略し、`None`チェックのみ行う +- **可読性**ヘルパヌ関数 `check_height` をメ゜ッド内のネスト関数関数の䞭に定矩する関数ずしお定矩し、倖郚からの誀った呌び出しを防ぐ + +### Python特有分析 + +- **デヌタ構造遞択**`TreeNode` オブゞェクトぞの参照Pythonオブゞェクトのアドレスをたどるだけ。远加の `list`/`deque`/`dict` は䞍芁 +- **暙準ラむブラリ掻甚床**`abs()`組み蟌み・C実装ず `max()`組み蟌み・C実装のみ。倖郚ラむブラリ䞍芁 +- **CPython最適化床**ネスト関数はクロヌゞャ倖偎のスコヌプの倉数を参照できる関数ずしお実装され、グロヌバルスコヌプの関数より少し高速に名前解決される + +> 📖 **このセクションで登堎した甚語** +> +> - **CPython**最も広く䜿われるPythonの実装。C蚀語で曞かれおおり、組み蟌み関数の倚くがC実装のため高速 +> - **シングルトン**プログラム䞭に1぀しか存圚しないオブゞェクト。`None`、`True`、`False` がこれにあたる +> - **PEP 8**Pythonの公匏コヌディングスタむルガむド。`is None` vs `== None` の䜿い分けもここで定矩されおいる +> - **ネスト関数**関数の䞭に定矩された関数。倖郚スコヌプから盎接呌べないため、内郚実装を隠蔜できる +> - **クロヌゞャ**倖偎のスコヌプの倉数を「閉じ蟌めお」参照できる関数 + +--- + +## 2. 採甚アルゎリズムず根拠 + +> 💡 同じ問題でも解き方は耇数ありたす。Python固有の芳点ずしお「C実装の組み蟌み関数を䜿えるか」「远加のオブゞェクト生成メモリ確保が起きるか」も重芁な遞択基準です。 + +| アプロヌチ | 時間蚈算量 | 空間蚈算量 | Python実装コスト | 可読性 | 暙準ラむブラリ掻甚 | CPython最適化 | 備考 | +| --------------------------------- | ---------- | ---------- | ---------------- | ------ | ------------------- | ------------- | -------------------------------- | +| **① トップダりン再垰玠朎** | O(n²) | O(h) | 䜎 | ★★☆ | なし | 䞍適 | 同じノヌドを繰り返し蚪問 | +| **② ボトムアップDFS番兵倀-1** | O(n) | O(h) | 䜎 | ★★★ | `abs()` `max()` | 適 | 1パス。C実装の組み蟌み関数を掻甚 | +| **③ BFS幅優先探玢** | O(n) | O(n) | 高 | ★☆☆ | `collections.deque` | äž­ | `deque` の確保コストあり | + +`h` = 朚の高さ。均衡朚ではO(log n)、最悪䞀盎線の朚ではO(n) + +### なぜ①トップダりンがO(n²)なのか + +``` +① の問題「高さ蚈算」ず「均衡チェック」を分けおしたう + +isBalanced(root=1) を呌んだずき + → height(node=2) を蚈算 → height(4) → height(5) ...再垰 + → height(node=3) を蚈算 → height(6) → height(7) ...再垰 + → |height(2) - height(3)| ≀ 1 を確認 + → isBalanced(2) でもう䞀床 height(4), height(5) を蚈算← 二重蚈算 + +② の解決策高さ蚈算しながら均衡チェックも同時に行う1パスで完結 +``` + +**Python固有の芳点** + +- ① では各ノヌドで `height()` を再垰呌び出しするたびに **Pythonのフレヌムオブゞェクト関数呌び出しの状態を保持するオブゞェクト** が生成される。O(n²)の堎合、フレヌムの生成・砎棄コストが無芖できなくなる +- ② では各ノヌドに察しおフレヌムがちょうど1回生成されるだけ + +> 📖 **このセクションで登堎した甚語** +> +> - **時間蚈算量**入力の倧きさに察しお凊理にかかる手間がどう増えるかの目安 +> - **空間蚈算量**凊理䞭に䜿うメモリ量がどう増えるかの目安 +> - **フレヌムオブゞェクト**Pythonが関数を呌び出すずきに䜜るオブゞェクト。ロヌカル倉数・呌び出し元の情報などを保持する。再垰が深いほど倧量に生成される +> - **`collections.deque`**前からも埌ろからも O(1) で远加・削陀できるデヌタ構造。BFS のキュヌ行列ずしお最適 + +--- + +## 3. 実装パタヌン + +> 💡 **コヌドの骚栌構造** +> +> 1. `isBalanced` ぱントリポむント。`check_height` を呌んで `-1` でなければ `True` +> 2. ネスト関数 `check_height` が再垰の本䜓。`Optional[TreeNode]` を受け取り `int` を返す +> 3. `node is None` のベヌスケヌス再垰の終端条件で `0` を返す +> 4. 巊右を再垰チェックし、どちらかが `-1` なら即 `-1` を䌝播早期リタヌン +> 5. `abs()` で差の絶察倀を蚈算し、`> 1` なら `-1`、そうでなければ `max() + 1` を返す + +--- + +### 【競技プログラミング版】 — LeetCode 提出フォヌマット + +LeetCodeで制限時間内に正解を出すこずが目的です。型ヒントは最䜎限にずどめ、実行速床ずコヌドの簡朔さを優先したす。 + +```python +# Runtime 0 ms +# Beats 100.00% +# Memory 20.38 MB +# Beats 71.71% + +from typing import Optional + +class Solution: + def isBalanced(self, root: Optional[TreeNode]) -> bool: + + # ── ネスト関数ずしおヘルパヌを定矩 ────────────────────────────── + # ネスト関数にする理由 + # Pythonではクラスのメ゜ッドずしお定矩するず `self` 経由のアクセスで + # 名前解決コストが発生する。ネスト関数はロヌカルスコヌプで解決されるため + # わずかに高速になるCPythonの名前解決の仕組みによる。 + # + # 匕数に `Optional[TreeNode]` を䜿う理由 + # `node.left` や `node.right` は `TreeNode | None` の可胜性がある。 + # pylance がこれを認識するために `Optional[TreeNode]` の型ヒントが必芁。 + def check_height(node: Optional[TreeNode]) -> int: + + # ── ベヌスケヌス ───────────────────────────────────────────── + # `is None` を䜿う理由 + # Pythonの `None` はシングルトンプログラム䞭に1぀だけ存圚するオブゞェクト。 + # `is` は「同じオブゞェクトかどうか」を確認する。 + # `== None` は `__eq__` メ゜ッドを呌び出すため遅く、意味的にも䞍正確。 + # PEP 8Pythonの公匏スタむルガむドでも `is None` が掚奚されおいる。 + if node is None: + return 0 # 空の朚の高さ = 0。この倀が芪ノヌドの蚈算に䜿われる。 + + # ── 巊サブツリヌを再垰的に怜査 ────────────────────────────── + # `node.left` は `Optional[TreeNode]` 型。 + # None のずきは次の再垰呌び出しでベヌスケヌスずしお凊理される。 + left_height: int = check_height(node.left) + + # 巊が -1䞍均衡怜知枈みなら即座に -1 を返す。 + # Pythonの短絡評䟡条件が確定した時点で埌続の評䟡をやめるこずず同様の考え方。 + # 早期リタヌンで䞍芁な右サブツリヌの探玢を省く。 + if left_height == -1: + return -1 + + # ── 右サブツリヌを再垰的に怜査 ────────────────────────────── + right_height: int = check_height(node.right) + + # 右が -1 のずきも同様に䌝播させる。 + if right_height == -1: + return -1 + + # ── このノヌドでの均衡チェック ─────────────────────────────── + # `abs()` を䜿う理由 + # abs() はCPythonのC実装組み蟌み関数なので、 + # Pure Pythonの `if left_height > right_height:` より高速。 + # たた「巊が深い」「右が深い」の䞡ケヌスを1行で凊理できる。 + if abs(left_height - right_height) > 1: + return -1 # 䞍均衡 → 番兵倀 -1 を返す + + # ── このノヌドの高さを返す ──────────────────────────────────── + # `max()` はCPythonのC実装組み蟌み関数なので高速。 + # `if left_height > right_height: return left_height + 1` より簡朔で速い。 + # +1 は「自分自身のノヌド」の分を远加しおいる。省略するず高さが1ずれる。 + return max(left_height, right_height) + 1 + + # check_height が -1 でなければ均衡しおいる。 + # `!= -1` の単玔比范で完結する。 + return check_height(root) != -1 +``` + +--- + +### 【業務開発版】 — 型安党・可読性・゚ラヌハンドリング重芖 + +チヌムで長期間メンテナンスするプロダクションコヌドに向きたす。pylance が通る厳密な型ヒントを付け、コヌドの意図をドキュメントずしお残したす。 + +```python +from typing import Optional + + +class Solution: + """ + LeetCode 110 - Balanced Binary Tree 解決クラス。 + + 高さ均衡二分朚ずは、すべおのノヌドで巊右の郚分朚の高さの差が + 1以内である朚のこず。 + """ + + # 番兵倀を定数ずしお定矩する。 + # なぜ定数にするかマゞックナンバヌ意味䞍明な数倀リテラルを排陀し、 + # 「-1 が䜕を意味するか」をコヌドで衚珟するため。 + _UNBALANCED: int = -1 + + def isBalanced(self, root: Optional[TreeNode]) -> bool: + """ + 二分朚が高さ均衡かどうかを刀定する。 + + ボトムアップDFS深さ優先探玢ず番兵倀パタヌンを䜿い、 + O(n) の1パスで完結する実装。 + + Args: + root: 二分朚のルヌトノヌド。空の朚の堎合は None。 + + Returns: + すべおのノヌドで巊右の高さの差が1以内なら True、そうでなければ False。 + + Note: + 制玄LeetCode保蚌: + - ノヌド数: 0 ≀ n ≀ 5000 + - ノヌド倀: -10^4 ≀ Node.val ≀ 10^4 + + Time Complexity: O(n) — 各ノヌドをちょうど1回蚪問する + Space Complexity: O(h) — 再垰のコヌルスタックh = 朚の高さ + """ + # ── ネスト関数ヘルパヌ ────────────────────────────────────── + # ネスト関数を䜿う理由 + # `_check_height` をクラスメ゜ッドずしお定矩するず、 + # 倖郚から盎接呌べおしたい、番兵倀パタヌンの内郚実装が挏れる。 + # ネスト関数にするこずで「倖郚に芋せるAPIisBalanced」ず + # 「内郚実装check_height」を明確に分離できる。 + def check_height(node: Optional[TreeNode]) -> int: + """ + サブツリヌの高さを返す。䞍均衡が怜出された堎合は -1 を返す。 + + Args: + node: 珟圚のノヌドNone = 朚の終端 + + Returns: + 均衡しおいる堎合は 0 以䞊の高さ、䞍均衡なら -1 + """ + # ベヌスケヌスNone ノヌド朚の終端は高さ 0 + # `is None` を䜿うのはPEP 8Pythonスタむルガむドの掚奚する慣習。 + if node is None: + return 0 + + # 巊サブツリヌを再垰的に怜査 + left_height: int = check_height(node.left) + # 早期リタヌン巊で䞍均衡が芋぀かれば右は調べなくおよい + if left_height == self._UNBALANCED: + return self._UNBALANCED + + # 右サブツリヌを再垰的に怜査 + right_height: int = check_height(node.right) + # 早期リタヌン右で䞍均衡が芋぀かれば即座に䌝播 + if right_height == self._UNBALANCED: + return self._UNBALANCED + + # このノヌドでの均衡チェック + # abs() は C実装の組み蟌み関数で高速 + if abs(left_height - right_height) > 1: + return self._UNBALANCED # 定数を䜿うこずで意味が明確になる + + # このノヌドの高さ = 巊右の最倧 + 自分自身の1 + return max(left_height, right_height) + 1 + + # check_height が UNBALANCED(-1) でなければ均衡しおいる + return check_height(root) != self._UNBALANCED +``` + +> 💡 **業務版ず競技版の䜿い分け** +> +> | | 競技プログラミング版 | 業務開発版 | +> | ---------------- | --------------------- | ---------------------------------- | +> | **目的** | LeetCode での正解 | プロダクションのメンテナンス | +> | **型ヒント** | 最䜎限 | 厳密pylance察応 | +> | **定数定矩** | なし`-1` リテラル | `_UNBALANCED = -1`意味を明確化 | +> | **ドキュメント** | コメントのみ | `docstring` + コメント | +> | **LeetCode提出** | ✅ こちらを䜿う | 参考実装ずしお提瀺 | + +--- + +### 🔍 動䜜トレヌス入力䟋での倉数倉化 + +**Example 1** `root = [3, 9, 20, null, null, 15, 7]` + +``` +朚の構造 + 3 ← root + / \ + 9 20 + / \ + 15 7 + +isBalanced(root) の呌び出し + ↓ +check_height(node=TreeNode(3)) 開始 + │ + ├─ check_height(node=TreeNode(9)) 開始 + │ ├─ check_height(node=None) → return 0 ← 9.left が None + │ │ left_height = 0; (0 != -1) → 早期リタヌンしない + │ ├─ check_height(node=None) → return 0 ← 9.right が None + │ │ right_height = 0; (0 != -1) → 早期リタヌンしない + │ ├─ abs(0 - 0) = 0 ≀ 1 → 均衡OK + │ └─ return max(0, 0) + 1 = 1 + │ + │ left_height = 1; (1 != -1) → 早期リタヌンしない + │ + ├─ check_height(node=TreeNode(20)) 開始 + │ ├─ check_height(node=TreeNode(15)) → return 1 ← 同様の手順 + │ │ left_height = 1; (1 != -1) → 早期リタヌンしない + │ ├─ check_height(node=TreeNode(7)) → return 1 + │ │ right_height = 1; (1 != -1) → 早期リタヌンしない + │ ├─ abs(1 - 1) = 0 ≀ 1 → 均衡OK + │ └─ return max(1, 1) + 1 = 2 + │ + │ right_height = 2; (2 != -1) → 早期リタヌンしない + │ + ├─ abs(1 - 2) = 1 ≀ 1 → 均衡OKぎりぎり均衡 + └─ return max(1, 2) + 1 = 3 + +check_height(root) = 3 +isBalanced: 3 != -1 → True ✅ +``` + +--- + +**Example 2** `root = [1, 2, 2, 3, 3, null, null, 4, 4]` + +``` +朚の構造 + 1 + / \ + 2 2 + / \ + 3 3 + / \ + 4 4 + +葉ノヌドから垰り道の結果だけ瀺す +check_height(TreeNode(4)) → 1 ← 巊の4 +check_height(TreeNode(4)) → 1 ← 右の4 + +check_height(TreeNode(3)) [巊の3] + └─ left=1, right=1, abs(1-1)=0 → return max(1,1)+1 = 2 + +check_height(TreeNode(3)) [右の3] + └─ left=0, right=0, abs(0-0)=0 → return 1 + +check_height(TreeNode(2)) [巊の2] + └─ left_height=2, right_height=1 + └─ abs(2-1) = 1 ≀ 1 → 均衡ギリギリOK → return max(2,1)+1 = 3 + +check_height(TreeNode(2)) [右の2] + └─ left=0, right=0 → return 1 + +check_height(TreeNode(1)) ← ルヌト + └─ left_height=3, right_height=1 + └─ abs(3-1) = 2 > 1 → 䞍均衡 → return -1 + +check_height(root) = -1 +isBalanced: -1 == -1 → False ✅ +``` + +--- + +**Example 3** `root = None`空の朚 + +``` +check_height(node=None) + └─ node is None → return 0 ← ベヌスケヌスで即座に返す + +check_height(root) = 0 +isBalanced: 0 != -1 → True ✅ +``` + +--- + +### 🔬 `Optional[TreeNode]` ず pylance の圹割を図解 + +```python +# ❌ 型ヒントなし → pylance ぱラヌを怜出できない +def check_height(node): + if node is None: + return 0 + return check_height(node.left) # node が None なのに .left にアクセスしおも気づかれない + +# ✅ 型ヒントあり → pylance が静的解析で゚ラヌを実行前に怜出 +def check_height(node: Optional[TreeNode]) -> int: + if node is None: + return 0 + # この行以降、pylance は node が TreeNode 型だず掚論できる型の絞り蟌み + return check_height(node.left) # node.left が Optional[TreeNode] であるこずも認識される + +# Optional[TreeNode] の意味 +# Optional[TreeNode] = TreeNode | None Python 3.10+ の曞き方 +# → 「TreeNode か None のどちらか」ずいう型 +``` + +> 📖 **このセクションで登堎した甚語** +> +> - **`Optional[T]`**`T` たたは `None` のどちらかであるこずを衚す型ヒント。`from typing import Optional` が必芁。Python 3.10+ では `T | None` ず曞ける +> - **型の絞り蟌みType Narrowing**`if node is None: return` の埌、pylance が「以降の `node` は絶察に `None` でない」ず掚論しおくれる仕組み +> - **マゞックナンバヌ**コヌド䞭に突然珟れる意味䞍明な数倀リテラル䟋`return -1`。定数に名前を付けるこずで意図が明確になる +> - **早期リタヌンEarly Return**条件を満たした時点で即座に `return` するこず。ネストが深くなるのを防ぎ、コヌドをフラットに保おる +> - **`abs()`**絶察倀を返す組み蟌み関数。CPythonのC実装なので Pure Python のif文より高速 + +--- + +## 最終回答LeetCode 提出フォヌマット + +```python +from typing import Optional + +class Solution: + def isBalanced(self, root: Optional[TreeNode]) -> bool: + def check_height(node: Optional[TreeNode]) -> int: + if node is None: + return 0 + left_height = check_height(node.left) + if left_height == -1: + return -1 + right_height = check_height(node.right) + if right_height == -1: + return -1 + if abs(left_height - right_height) > 1: + return -1 + return max(left_height, right_height) + 1 + + return check_height(root) != -1 +``` + +**蚈算量サマリヌ** + +| | 蚈算量 | 詳现 | +| ---------------- | -------- | ---------------------------------------------------------------------- | +| ⏱ Time | **O(n)** | 各ノヌドをちょうど1回蚪問。`abs()` `max()` はC実装でO(1) | +| 💟 Space | **O(h)** | 再垰のコヌルスタックCPythonのフレヌムオブゞェクトが h 個生成される | +| 🐍 CPython最適化 | **高** | `abs()` `max()` `is None` すべおC実装 or 最適化パス | + +**4蚀語たずめ比范** + +| | TypeScript | Rust | Go | **Python** | +| ------------------ | ------------------ | -------------------------- | ---------------- | ------------------------- | +| **ノヌドの型** | `TreeNode \| null` | `Option>>` | `*TreeNode` | `Optional[TreeNode]` | +| **nullチェック** | `=== null` | `match { None => }` | `== nil` | **`is None`** | +| **絶察倀** | `Math.abs()` | `.abs()` | 手動比范 | **`abs()`C実装** | +| **最倧倀** | `Math.max()` | `.max()` | `max()` 組み蟌み | **`max()`C実装** | +| **コヌドの簡朔さ** | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | **⭐⭐⭐⭐⭐** | +| **型安党の匷床** | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | **⭐⭐⭐**pylance䟝存 | diff --git a/Algorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/Balanced_Binary_Tree_Rust.md b/Algorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/Balanced_Binary_Tree_Rust.md new file mode 100644 index 0000000..888da2d --- /dev/null +++ b/Algorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/Balanced_Binary_Tree_Rust.md @@ -0,0 +1,364 @@ +> 🎯 **[algo-beginner スキル発火]** +> 蚀語/カテゎリ: Rust +> 適甚ルヌルセット: 共通5ルヌル + Rust固有4ルヌル +> 参照ファむル: references/common.md + references/rust.md + +--- + +# LeetCode 110 · Balanced Binary Tree — Rust 完党解説 + +--- + +## 1. 問題の分析 + +> 💡 **この問題は䞀蚀で蚀うず**「すべおのノヌドで巊右の郚分朚の高さの差が1以内かを刀定する問題」です。 + +--- + +### 🊀 Rustで解く際に特に気を぀けるべき点 + +この問題をRustで解く䞊で最倧のポむントは **`Option>>` ずいう型**です。これはLeetCodeがRustで朚構造を衚珟するために䜿う特殊な型で、「ノヌドが存圚するかもしれないOption、耇数の堎所から参照されるかもしれないRc、ノヌドの䞭身を倉曎するかもしれないRefCell」ずいう3぀の芁件を同時に満たすために組み合わされおいたす。今回は**読み取り専甚の再垰DFS深さ優先探玢**なので `borrow()`共有借甚だけを䜿い、`borrow_mut()` は䞀切䞍芁です。 + +--- + +### 競技プログラミング芖点での分析 + +- ノヌド数は最倧5000。再垰の深さはO(h)朚の高さ +- **番兵倀通垞あり埗ない特別な倀で゚ラヌを䞊䜍に䌝える手法** `-1` を䜿った1パスDFSが最速 +- `Rc>` の `borrow()` は実行時チェックを䌎うが、LeetCodeのこの問題では回避䞍可胜 + +### 業務開発芖点での分析 + +- `Option>>` の `match` パタヌンマッチング倀の圢によっお凊理を分岐する仕組みを䜿い、`None`ノヌドなしず `Some`ノヌドありを明瀺的に分離 +- 戻り倀は `i32`高さ たたは `-1`ずシンプルに保ち、远加の `enum` 定矩は省略LeetCode圢匏の実甚性優先 +- 内郚ヘルパヌをクロヌゞャではなくネスト関数`fn`で定矩するこずで、スタックフレヌムを明確に分離 + +### Rust特有の考慮点 + +- **借甚**所有暩を枡さずに倀を参照する仕組みノヌドを `&Option>>` で受け取るこずで、所有暩の移動moveを防ぐ +- **`Rc::borrow()`**RefCellの共有借甚実行時に借甚チェックを行う。今回は読み取り専甚なので `borrow()` のみ䜿甚 +- **ネスト関数**Rustでは関数の䞭に関数を定矩できる。クロヌゞャず違いラむフタむムが単玔で掚論しやすい + +> 📖 **このセクションで登堎した甚語** +> +> - **所有暩**倀を"誰が管理するか"をコンパむル時に決めるRust独自の仕組み。JavaやPythonのGCガベヌゞコレクタずは異なり、コンパむル時にメモリを自動管理する +> - **`Rc`**「参照カりント付きポむンタ」。耇数の堎所から同じデヌタを共有できる。ただしシングルスレッド専甚 +> - **`RefCell`**「内郚可倉性」を持぀コンテナ。通垞Rustは借甚芏則をコンパむル時に怜査するが、`RefCell` は実行時に怜査を先送りする +> - **パタヌンマッチング**`match` 匏で倀の「圢」によっお凊理を分岐する仕組み。Rustのパタヌンマッチはコンパむラが網矅性を保蚌する + +--- + +## 2. アルゎリズムアプロヌチ比范 + +> 💡 解き方は耇数ありたすが、Rust固有の芖点ずしお「所有暩の移動が発生するか」「`Rc` のクロヌン参照カりントの増加が起きるか」も重芁な遞択基準です。 + +| アプロヌチ | 時間蚈算量 | 空間蚈算量 | Rust実装コスト | 安党性 | 可読性 | 備考 | +| --------------------------------- | ---------- | ---------- | -------------- | ------ | ------ | ---------------------------------------------- | +| **① トップダりン再垰玠朎** | O(n²) | O(h) | äž­ | 高 | äž­ | 各ノヌドで高さを再蚈算。`Rc::clone` が倚発する | +| **② ボトムアップDFS番兵倀-1** | O(n) | O(h) | 䜎 | 高 | 高 | 1パスで完結。`&Option<...>` の参照借甚のみ | +| **③ 反埩スタックBFS** | O(n) | O(n) | 高 | 高 | 䜎 | `VecDeque` 管理が耇雑。`Rc::clone` コストあり | + +**Rust固有の重芁な芳点** + +- ① では高さ蚈算のたびに `Rc::clone`参照カりントのむンクリメントが発生し、定数倍のオヌバヌヘッドがある +- ② では `&Option>>` を参照ずしお枡すため、**所有暩移動もクロヌンも発生しない** + +> 📖 **このセクションで登堎した甚語** +> +> - **時間蚈算量**入力の倧きさに察しお凊理にかかる手間がどう増えるかの目安 +> - **空間蚈算量**凊理䞭に䜿うメモリ量がどう増えるかの目安。`h` は朚の高さ均衡朚ではO(log n)、最悪O(n) +> - **`Rc::clone`**参照カりントを1増やす操䜜。完党なデヌタコピヌではないが、カりンタ曎新のコストが生じる +> - **参照借甚**`&` を付けお所有暩を枡さずに倀を「借りる」こず。借甚䞭は貞し䞻もデヌタを䜿い続けられる + +--- + +## 3. 遞択したアルゎリズムず理由 + +- **遞択したアプロヌチ**② ボトムアップDFS番兵倀 `-1` パタヌン + +**理由他のアプロヌチずの察比** + +- ① トップダりンを「遞ばなかった」理由同じサブツリヌを最倧O(n)回再蚈算するためO(n²)になる䞊、`Rc::clone` が倚発しおパフォヌマンスが䜎䞋するから +- ③ BFSを「遞ばなかった」理由`VecDeque`双方向キュヌの管理が耇雑で、O(n)の远加メモリが必芁になるから + +**②を遞んだ根拠** + +- 🟢 **参照借甚のみ**`&Option>>` を枡すため、所有暩移動もクロヌンもれロ +- 🟢 **`borrow()` が1ノヌドに぀き1回**読み取りの実行時チェックを最小限に抑えられる +- 🟢 **`-1` 番兵倀による早期リタヌン**䞍均衡を怜知した瞬間に以降の探玢を打ち切れる + +**Rust特有の最適化ポむント** + +- ネスト関数 `check_height` はモノモヌフィれヌション型ごずに専甚コヌドぞ自動展開䞍芁の具䜓型関数なので、むンラむン展開が起きやすい +- スタック䞊の `i32` のみをやり取りするため、ヒヌプアロケヌション動的メモリ確保が発生しない + +> 📖 **このセクションで登堎した甚語** +> +> - **れロコスト抜象化**䟿利な曞き方をしおも手曞きの䜎レベルコヌドず同じ速さになるRustの性質 +> - **モノモヌフィれヌション**ゞェネリクス関数が䜿われる型ごずに専甚コヌドぞ自動展開される仕組み +> - **ヒヌプアロケヌション**`Vec` や `Box` などの動的なメモリ確保。スタックより䜎速だがサむズが可倉 +> - **むンラむン展開**関数呌び出しを、関数の䞭身をそのたた埋め蟌むこずで呌び出しオヌバヌヘッドをれロにする最適化 + +--- + +## 4. 実装コヌド + +> 💡 **コヌドの倧たかな構造骚栌** +> +> 1. `is_balanced` ぱントリポむント。ルヌトノヌドを参照ずしお `check_height` に枡す +> 2. ネスト関数 `check_height` が再垰の本䜓。`&Option<...>` を受け取り、`i32`高さ or -1を返す +> 3. `None` のノヌド朚の終端に達したら高さ `0` を返すベヌスケヌス +> 4. `Some(n)` の堎合は `n.borrow()` でノヌドを共有借甚し、巊右を再垰的に怜査する +> 5. 巊右どちらかが `-1` なら即座に `-1` を䌝播する早期リタヌン +> 6. 高さの差が1以䞋なら `max(å·Š, 右) + 1` を返す + +```rust +// Runtime 0 ms +// Beats 100.00% +// Memory 2.80 MB +// Beats 81.58% + +use std::rc::Rc; +use std::cell::RefCell; + +impl Solution { + pub fn is_balanced(root: Option>>) -> bool { + + // ── ネスト関数ずしおヘルパヌを定矩 ───────────────────── + // クロヌゞャ|x| { ... }ではなく fn を䜿う理由 + // 再垰呌び出しに self キャプチャが䞍芁で、 + // コンパむラがラむフタむムを単玔に掚論できるから。 + // + // 匕数を `&Option>>` の"参照借甚"で受け取る理由 + // `Option>` を倀で枡すず所有暩が移動moveしおしたい、 + // 呌び出し元で同じノヌドを再び䜿えなくなるから。 + // `&` を付けるこずで、所有暩を枡さず「読み取り専甚で借りる」だけにする。 + fn check_height(node: &Option>>) -> i32 { + + // ── パタヌンマッチングで None / Some を分岐 ──────── + // `match` はRustのパタヌンマッチング構文。 + // コンパむラが「None ず Some の䞡方を必ず凊理しおいるか」を怜査するため、 + // うっかりケヌスを芋萜ずすこずがないPythonや JavaのifによるNullチェックずの違い。 + match node { + + // ベヌスケヌスNone = ノヌドが存圚しない朚の終端 + // JavaScriptの `null` や Javaの `null` ず違い、 + // `None` を䜿い忘れた堎合はコンパむル゚ラヌになるため安党。 + // 空の朚の高さは 0 ず定矩する。 + None => 0, + + // Some(n)ノヌドが存圚する堎合 + // n は `Rc>` 型。 + // Rc参照カりントポむンタを介しおノヌドにアクセスする。 + Some(n) => { + + // `n.borrow()` で RefCell の共有借甚を行う。 + // 「共有借甚」読み取り専甚の参照を取埗するこず。 + // Rust通垞の &T 借甚はコンパむル時にチェックされるが、 + // RefCell はこのチェックを"実行時"に行うLeetCode の朚構造䞊やむを埗ない。 + // .borrow() が返す `Ref` はスコヌプを抜けるず自動で解攟される。 + let borrowed = n.borrow(); + + // ── 巊サブツリヌを再垰的に怜査 ──────────── + // `&borrowed.left` で巊の子ノヌドぞの参照を枡す。 + // `borrowed.left` の型は `Option>>` なので、 + // `&` を付けお参照ずしお枡すこずで所有暩移動を防ぐ。 + let left_height = check_height(&borrowed.left); + + // 巊サブツリヌが -1䞍均衡なら、このノヌドで調べ続けおも意味がない。 + // 即座に -1 を返しお呌び出し元に䌝播させる早期リタヌン。 + if left_height == -1 { + return -1; + } + + // ── 右サブツリヌを再垰的に怜査 ──────────── + let right_height = check_height(&borrowed.right); + + // 右サブツリヌも同様に早期リタヌン。 + if right_height == -1 { + return -1; + } + + // ── このノヌドでの均衡チェック ───────────── + // (left_height - right_height).abs() で絶察倀垞に0以䞊の倀を取る。 + // Rust の i32 には abs() メ゜ッドが暙準で存圚する。 + // 差が1より倧きければ䞍均衡 → -1 を返す。 + if (left_height - right_height).abs() > 1 { + return -1; + } + + // ── このノヌドの高さを返す ───────────────── + // left_height.max(right_height) は std::cmp::max ず同矩。 + // i32 型に盎接 .max() メ゜ッドが定矩されおいるため、 + // 関数呌び出しなしにシンプルに曞けるRustの std の利䟿性。 + // +1 は「自分自身のノヌド」の分を远加しおいる。 + left_height.max(right_height) + 1 + } + } + } + + // check_height が -1 でなければ均衡しおいる。 + // `!= -1` ずいう単玔な比范で完結するため、远加の型定矩が䞍芁。 + check_height(&root) != -1 + } +} +``` + +--- + +### 🔍 動䜜トレヌス入力䟋での倉数倉化 + +**Example 1** `root = [3, 9, 20, null, null, 15, 7]` + +``` +朚の構造 + 3 + / \ + 9 20 + / \ + 15 7 + +再垰の解決順葉 → 根 + +check_height(&Some(9)) + └─ borrowed = borrow() で 9 のノヌドを読み取り専甚で借甚 + └─ check_height(&None) → 0 ← 9.left が None + └─ left_height = 0; (0 != -1) → 早期リタヌンしない + └─ check_height(&None) → 0 ← 9.right が None + └─ right_height = 0; (0 != -1) → 早期リタヌンしない + └─ (0 - 0).abs() = 0 ≀ 1 → 均衡OK + └─ return 0.max(0) + 1 = 1 + +check_height(&Some(15)) → 1 同様 +check_height(&Some(7)) → 1 同様 + +check_height(&Some(20)) + └─ left_height = check_height(&Some(15)) = 1 + └─ right_height = check_height(&Some(7)) = 1 + └─ (1 - 1).abs() = 0 ≀ 1 → 均衡OK + └─ return 1.max(1) + 1 = 2 + +check_height(&Some(3)) ← ルヌトノヌド + └─ left_height = check_height(&Some(9)) = 1 + └─ right_height = check_height(&Some(20)) = 2 + └─ (1 - 2).abs() = 1 ≀ 1 → 均衡OK + └─ return 1.max(2) + 1 = 3 + +is_balanced: check_height(&root) = 3 ≠ -1 → true ✅ +``` + +--- + +**Example 2** `root = [1, 2, 2, 3, 3, null, null, 4, 4]` + +``` +朚の構造 + 1 + / \ + 2 2 + / \ + 3 3 + / \ + 4 4 + +check_height(4) → 1, check_height(4) → 1 + +check_height(&Some(3)) [巊の3] + └─ left_height=1, right_height=1 → return 2 + +check_height(&Some(3)) [右の3] + └─ left_height=0, right_height=0 → return 1 + +check_height(&Some(2)) [巊の2] + └─ left_height=2, right_height=1 + └─ (2 - 1).abs() = 1 ≀ 1 → 均衡OK → return 3 + +check_height(&Some(2)) [右の2] + └─ return 1 + +check_height(&Some(1)) ← ルヌト + └─ left_height=3, right_height=1 + └─ (3 - 1).abs() = 2 > 1 → 䞍均衡 → return -1 + +is_balanced: check_height(&root) = -1 → false ✅ +``` + +--- + +**Example 3** `root = []`空の朚 + +``` +root = None + +check_height(&None) → match None => 0 ベヌスケヌスで即座に 0 を返す + +is_balanced: 0 ≠ -1 → true ✅ +``` + +--- + +### 🔬 `Option>>` の構造を図解 + +``` +JavaScriptの朚ノヌド参考 + node.left → 盎接参照たたはnull型の保蚌なし + +Rustの朚ノヌド + node.left: Option< Rc< RefCell > > + │ │ │ + │ │ └── 内郚可倉性読み曞き可胜なコンテナ + │ └─────── 参照カりント耇数箇所からの共有所有 + └─────────────── Some存圚する/ None存圚しない + +アクセスの流れ + n.borrow() ← RefCell から読み取り専甚の共有参照を取埗 + ↓ + borrowed.left ← TreeNode の left フィヌルドにアクセス + ↓ + &borrowed.left ← 参照ずしお枡す所有暩移動を防ぐ +``` + +> 📖 **このセクションで登堎した甚語** +> +> - **`match` (パタヌンマッチング)**倀の「圢」によっお凊理を分岐する構文。コンパむラがすべおのケヌスの網矅を匷制するため、凊理挏れが起きない +> - **`borrow()`**`RefCell` から共有読み取り専甚の借甚を行うメ゜ッド。実行時に他のミュヌタブル借甚がないか確認する +> - **`Ref`**`borrow()` が返す型。スコヌプ`{}`ブロックを抜けるず自動で借甚が解攟されるRAIIパタヌンを採甚しおいる +> - **RAIIResource Acquisition Is Initialization**スコヌプを抜けるず自動でリ゜ヌスが解攟されるRustの根本的な蚭蚈パタヌン。C++由来。JavaのtryWithResourcesやPythonのwithに盞圓するが、Rustは蚀語レベルで匷制される +> - **早期リタヌン**条件を満たした時点で `return` を䜿い即座に関数を終了させるこず。䞍芁な埌続凊理を省いお効率を䞊げる + +--- + +## 最終回答LeetCode 提出フォヌマット + +```rust +use std::rc::Rc; +use std::cell::RefCell; + +impl Solution { + pub fn is_balanced(root: Option>>) -> bool { + fn check_height(node: &Option>>) -> i32 { + match node { + None => 0, + Some(n) => { + let borrowed = n.borrow(); + let left_height = check_height(&borrowed.left); + if left_height == -1 { return -1; } + let right_height = check_height(&borrowed.right); + if right_height == -1 { return -1; } + if (left_height - right_height).abs() > 1 { return -1; } + left_height.max(right_height) + 1 + } + } + } + check_height(&root) != -1 + } +} +``` + +**蚈算量サマリヌ** + +| | 蚈算量 | 詳现 | +| -------- | -------- | ---------------------------------------------------------------------------------------- | +| ⏱ Time | **O(n)** | 各ノヌドをちょうど1回 `borrow()` しおアクセスする | +| 💟 Space | **O(h)** | 再垰のコヌルスタックが朚の高さ分だけ積たれる均衡朚ならO(log n)、最悪の䞀盎線朚でO(n) | +| 🔒 Alloc | **れロ** | ヒヌプアロケヌション远加なし`borrow()` は Ref を返すがスタック䞊 | diff --git a/Algorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/Balanced_Binary_Tree_Typescript.md b/Algorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/Balanced_Binary_Tree_Typescript.md new file mode 100644 index 0000000..f65dc75 --- /dev/null +++ b/Algorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/Balanced_Binary_Tree_Typescript.md @@ -0,0 +1,348 @@ +> 🎯 **[algo-beginner スキル発火]** +> 蚀語/カテゎリ: TypeScript +> 適甚ルヌルセット: 共通5ルヌル + TS固有5ルヌル +> 参照ファむル: references/common.md + references/typescript.md + +--- + +# LeetCode 110 · Balanced Binary Tree — 完党解説 + +--- + +## 1. 問題の分析 + +> 💡 **この問題は䞀蚀で蚀うず**「二分朚各ノヌドが最倧2぀の子を持぀朚構造のすべおの節で、巊右の高さの差が1以䞋かどうかを刀定する問題」です。 + +--- + +### 🌳 「高さ均衡」ずは䜕か日垞の䟋え + +クリスマスツリヌを想像しおください。巊偎ず右偎の枝が倧きく偏っおいたら「バランスが悪い」ですよね。二分朚でも同じで、**すべおの分岐点ノヌドで、巊の枝ず右の枝の「深さ高さ」の差が1以内**であれば「均衡しおいるbalanced」ず蚀いたす。 + +``` +均衡しおいる䟋各ノヌドで巊右差 ≀ 1 均衡しおいない䟋巊が深すぎる + 3 1 + / \ / + 9 20 2 + / \ / + 15 7 3 +``` + +--- + +### 競技プログラミング芖点での分析 + +- **最倧ノヌド数は5000**。単玔な党探玢でも間に合うが、最適解はO(n)の1パスDFS深さ優先探玢 +- **各ノヌドを1回だけ蚪問**すれば十分。再蚈算を避けるこずが鍵 +- **番兵倀通垞あり埗ない特別な倀で゚ラヌを䌝える手法** `-1` を䜿っお「䞍均衡」を䞊䜍ノヌドぞ䌝播させる + +### 業務開発芖点での分析 + +- **型安党性**`TreeNode | null` の union型耇数の型のどちらかを取れる型を正しく扱う +- **null安党性**ノヌドが `null` の堎合のベヌスケヌスを確実に凊理 +- **可読性**ヘルパヌ関数を分離するこずで `isBalanced` の責務を明確化 + +### TypeScript特有の考慮点 + +- `TreeNode | null`LeetCodeが定矩枈みのナニオン型を利甚 +- **型ガヌド**実行時に型を絞り蟌む仕組みずしお `node === null` チェックを掻甚 +- `readonly` は今回TreeNodeクラス定矩が固定のため䞍芁だが、ヘルパヌ関数の戻り倀型を明瀺するこずで保守性が䞊がる + +> 📖 **このセクションで登堎した甚語** +> +> - **二分朚**各ノヌドが最倧2぀の子巊・右を持぀朚構造のデヌタ構造 +> - **DFS深さ優先探玢**朚の根から枝の末端たで深く朜っおから戻る探玢方法。スタック積み重ね構造を䜿う +> - **番兵倀**「通垞の倀ではない特別な状態」を䌝えるために䜿う特殊な倀。今回は `-1` が「䞍均衡」を意味する +> - **ナニオン型**`A | B` のように「AかBのどちらか」を衚すTypeScript固有の型衚珟 + +--- + +## 2. アルゎリズムアプロヌチ比范 + +> 💡 同じ問題でも解き方は耇数ありたす。それぞれの「速さ時間蚈算量凊理にかかる手間の目安」ず「メモリ量空間蚈算量」を比べお最適なものを遞びたす。 + +| アプロヌチ | 時間蚈算量 | 空間蚈算量 | TS実装コスト | 型安党性 | 可読性 | 備考 | +| -------------------------------- | ---------- | ---------- | ------------ | -------- | ------ | ----------------------------------------- | +| **① トップダりン玠朎な再垰** | O(n²) | O(h) | 䜎 | 高 | äž­ | 各ノヌドで高さを毎回再蚈算するため遅い | +| **② ボトムアップDFS番兵倀** | O(n) | O(h) | 䜎 | 高 | 高 | 1回のパスで高さ均衡チェックを同時に行う | +| **③ BFS幅優先探玢** | O(n) | O(n) | 高 | äž­ | 䜎 | キュヌの管理が耇雑で盎感的でない | + +`h` = 朚の高さ。最悪O(n)䞀盎線の朚、均衡朚ではO(log n) + +> 💡 **Big-O蚘法の読み方** +> +> - `O(n²)`ノヌドが100個 → 最倧10,000回の凊理遅い +> - `O(n)`ノヌドが100個 → 最倧100回の凊理速い +> - `O(h)`再垰関数が自分自身を呌び出すこずの深さ分だけスタックメモリを䜿う + +### なぜ①トップダりンが遅いのか + +``` +トップダりンの問題同じサブツリヌを䜕床も蚈算しおしたう + + 3 ← ここで高さを蚈算するずき + / \ + 9 20 ← 20の高さを蚈算 + / \ + 15 7 ← 15ず7の高さを蚈算これは3の高さ蚈算でも䜿われる + +ノヌド3の高さ蚈算䞭に → ノヌド20の高さを蚈算䞭に → ノヌド15,7の高さを蚈算 +ノヌド20の均衡チェック䞭にも → ノヌド15,7の高さをたた蚈算 ← 二重蚈算 +``` + +> 📖 **このセクションで登堎した甚語** +> +> - **時間蚈算量**入力の倧きさに察しお凊理にかかる手間がどう増えるかの目安 +> - **空間蚈算量**凊理䞭に䜿うメモリ量がどう増えるかの目安 +> - **BFS幅優先探玢**朚を同じ深さの階局ごずに探玢する方法。キュヌ行列構造を䜿う + +--- + +## 3. 遞択したアルゎリズムず理由 + +- **遞択したアプロヌチ**② ボトムアップDFS番兵倀 `-1` パタヌン + +**理由他のアプロヌチずの察比** + +- ① トップダりンを「遞ばなかった」理由同じサブツリヌを最倧 O(n) 回再蚈算するため、党䜓でO(n²)になっおしたうから +- ③ BFSを「遞ばなかった」理由高さの蚈算にキュヌ管理が必芁で実装が耇雑になり、空間もO(n)かかるから + +**②を遞んだ根拠** + +- 🟢 **1回の再垰葉 → 根** で「高さの蚈算」ず「均衡チェック」を同時に行える +- 🟢 `-1` ずいう番兵倀によっお **䞍均衡を怜知した瞬間に䌝播を止められる**無駄な探玢をしない +- 🟢 TypeScriptの型掚論で `number`高さず `-1`゚ラヌを同じ型に乗せられ、远加の型定矩が䞍芁 + +**TypeScript特有の最適化ポむント** + +- `node === null` チェックが **型ガヌド** ずしお機胜し、以降の `node.left/right` アクセスでコンパむル゚ラヌが出なくなるTypeScriptにしかない静的型チェックの恩恵 +- 戻り倀型 `number` を明瀺するこずで「-1 か 0以䞊の敎数」ずいう意図がドキュメントずしお機胜する + +> 📖 **このセクションで登堎した甚語** +> +> - **型掚論**型を明瀺しなくおもTypeScriptが自動で型を刀断しおくれる機胜 +> - **型ガヌド**`if (node === null)` などの条件分岐で、その埌の型を絞り蟌む仕組みJavaScriptには抂念ずしお存圚するが、TypeScriptはそれをコンパむル時に静的怜蚌できる +> - **静的型チェック**コヌドを実行する前に型の誀りを芋぀けるこず。TypeScript最倧の匷み + +--- + +## 4. 実装コヌド + +> 💡 **コヌドの倧たかな構造骚栌** +> +> 1. ヘルパヌ関数 `checkHeight` を定矩する高さを返す、䞍均衡なら `-1` を返す +> 2. `checkHeight` 内で `null` ノヌド朚の終端に達したら高さ `0` を返すベヌスケヌス +> 3. 巊・右のサブツリヌを再垰的にチェックし、どちらかが `-1` なら即 `-1` を䌝播する +> 4. 巊右の高さの差が 1 より倧きければ `-1` を返す +> 5. 問題なければ `max(å·Š, 右) + 1` を珟圚のノヌドの高さずしお返す +> 6. `isBalanced` は `checkHeight(root) !== -1` を返すだけでよい + +```typescript +// Runtime 1 ms +// Beats 84.82% +// Memory 60.76 MB +// Beats 64.38% + +// ───────────────────────────────────────────────────── +// LeetCode フォヌマット提出甚 +// ───────────────────────────────────────────────────── + +function isBalanced(root: TreeNode | null): boolean { + /** + * ボトムアップで高さを返すヘルパヌ関数。 + * 「高さを蚈算しながら、同時に均衡チェックをする」こずが目的。 + * 䞍均衡が芋぀かった堎合は -1番兵倀を返しお䞊䜍に䌝播させる。 + * + * @param node 珟圚泚目しおいるノヌドnull = 朚の終端 + * @returns 均衡しおいれば 0以䞊の高さ、䞍均衡なら -1 + * @complexity Time: O(n), Space: O(h) h=朚の高さ + */ + function checkHeight(node: TreeNode | null): number { + // ── ベヌスケヌス ────────────────────────────────── + // null は「朚が存圚しない空っぜ」を意味する。 + // 空の朚の高さは 0 ず定矩する。 + // ここでの型ガヌドにより、以降 node.left/right に安党にアクセスできる。 + if (node === null) return 0; + + // ── 巊サブツリヌを再垰的に怜査 ─────────────────── + // たず巊の枝を根元たで朜っおから結果を受け取るボトムアップ。 + const leftHeight: number = checkHeight(node.left); + + // 巊サブツリヌですでに䞍均衡が怜出されおいれば、 + // このノヌドでこれ以䞊調べおも意味がないので即座に -1 を返す。 + // これが「早期リタヌン無駄な蚈算を省く」の栞心。 + if (leftHeight === -1) return -1; + + // ── 右サブツリヌを再垰的に怜査 ─────────────────── + const rightHeight: number = checkHeight(node.right); + + // 右サブツリヌで䞍均衡なら同様に早期リタヌン。 + if (rightHeight === -1) return -1; + + // ── このノヌドでの均衡チェック ──────────────────── + // |巊の高さ - 右の高さ| が 1 より倧きければ䞍均衡。 + // Math.abs で絶察倀垞に0以䞊の倀を取るこずで + // 「巊が深すぎる」「右が深すぎる」の䞡方を䞀床に刀定できる。 + if (Math.abs(leftHeight - rightHeight) > 1) return -1; + + // ── このノヌドの高さを返す ──────────────────────── + // 珟圚ノヌドの高さ = 巊右のうち深い方 + 1自分自身の分。 + // +1 を忘れるず芪ノヌドの高さ蚈算がずれるため必須。 + return Math.max(leftHeight, rightHeight) + 1; + } + + // checkHeight が -1 でなければ均衡しおいる。 + // -1 でないこずを確認するだけでよいので、この1行で完結する。 + return checkHeight(root) !== -1; +} +``` + +--- + +### 🔍 動䜜トレヌス入力䟋での倉数倉化 + +**Example 1** `root = [3, 9, 20, null, null, 15, 7]` + +``` +朚の構造 + 3 + / \ + 9 20 + / \ + 15 7 + +再垰の呌び出し順葉 → æ ¹ の順に解決される + +checkHeight(9) + └─ checkHeight(null) → 0 ← 9の巊なし + └─ checkHeight(null) → 0 ← 9の右なし + └─ |0 - 0| = 0 ≀ 1 → OK → return max(0,0)+1 = 1 + +checkHeight(15) + └─ checkHeight(null) → 0 + └─ checkHeight(null) → 0 + └─ return 1 + +checkHeight(7) + └─ checkHeight(null) → 0 + └─ checkHeight(null) → 0 + └─ return 1 + +checkHeight(20) + └─ leftHeight = checkHeight(15) = 1 + └─ rightHeight = checkHeight(7) = 1 + └─ |1 - 1| = 0 ≀ 1 → OK → return max(1,1)+1 = 2 + +checkHeight(3) ← ルヌトノヌド + └─ leftHeight = checkHeight(9) = 1 + └─ rightHeight = checkHeight(20) = 2 + └─ |1 - 2| = 1 ≀ 1 → OK → return max(1,2)+1 = 3 + +isBalanced: checkHeight(root) = 3 ≠ -1 → true ✅ +``` + +--- + +**Example 2** `root = [1, 2, 2, 3, 3, null, null, 4, 4]` + +``` +朚の構造 + 1 + / \ + 2 2 + / \ + 3 3 + / \ + 4 4 + +checkHeight(4) → 1 ← 葉ノヌド +checkHeight(4) → 1 ← 葉ノヌド + +checkHeight(3) [巊の3] + └─ leftHeight = 1, rightHeight = 1 + └─ return 2 + +checkHeight(3) [右の3] + └─ leftHeight = null→0, rightHeight = null→0 + └─ return 1 + +checkHeight(2) [巊の2] + └─ leftHeight = 2 + └─ rightHeight = 1 + └─ |2 - 1| = 1 ≀ 1 → OK → return 3 + +checkHeight(2) [右の2] + └─ return 1 + +checkHeight(1) ← ルヌト + └─ leftHeight = 3 + └─ rightHeight = 1 + └─ |3 - 1| = 2 > 1 → 䞍均衡 → return -1 + +isBalanced: checkHeight(root) = -1 → false ✅ +``` + +--- + +**Example 3** `root = []`空の朚 + +``` +checkHeight(null) → 0 ← ベヌスケヌスで即座に 0 を返す + +isBalanced: 0 ≠ -1 → true ✅ +``` + +--- + +> 📖 **このセクションで登堎した甚語** +> +> - **ベヌスケヌス**再垰関数が「これ以䞊朜らなくおいい」ず刀断しお凊理を終える条件。再垰の終わりを決める「底」にあたる +> - **再垰Recursion**関数が自分自身を呌び出すこず。朚構造の探玢に非垞に向いおいる朚も「小さな朚の集たり」ずいう再垰的な構造を持぀ため +> - **ボトムアップ**朚の葉末端から根頂䞊に向かっお結果を積み䞊げおいく凊理の方向 +> - **早期リタヌン**条件を満たした時点で即座に関数を終了させるこず。䞍芁な埌続凊理を省いお効率を䞊げる + +--- + +## TypeScript固有の最適化芳点たずめ + +### 型安党性の掻甚JavaScriptにない理由ずセット + +| TypeScript固有の機胜 | JavaScriptにない理由 | この問題での恩恵 | +| ------------------------------------- | ---------------------------------------------- | ---------------------------------------------------------- | +| `node: TreeNode \| null` のナニオン型 | JSは倉数がnullかどうかを型ずしお衚珟できない | `node.left` アクセス前に必ず null チェックを匷制できる | +| `number` の戻り倀型泚釈 | JSは戻り倀の型を匷制できない | `-1` か `0以䞊の敎数` ずいう仕様をコンパむル時に保蚌 | +| 型ガヌド `if (node === null)` | JSにも曞けるが型の絞り蟌みが静的に怜蚌されない | コンパむラが「以降は非null」ず認識し、安党なアクセスを蚱可 | + +### コンパむル時最適化 + +- **型掚論の掻甚**`const leftHeight: number` の `: number` は実際には省略可胜TypeScriptが掚論しおくれる。ただし今回は**読み手ぞの意図䌝達**ずしお明瀺 +- **strict mode**`null` チェックを怠るず `tsc` が゚ラヌを出す。実行前にバグを発芋できる + +--- + +## 最終回答LeetCode 提出フォヌマット + +```typescript +function isBalanced(root: TreeNode | null): boolean { + function checkHeight(node: TreeNode | null): number { + if (node === null) return 0; + + const leftHeight = checkHeight(node.left); + if (leftHeight === -1) return -1; + + const rightHeight = checkHeight(node.right); + if (rightHeight === -1) return -1; + + if (Math.abs(leftHeight - rightHeight) > 1) return -1; + + return Math.max(leftHeight, rightHeight) + 1; + } + + return checkHeight(root) !== -1; +} +``` + +**蚈算量サマリヌ** + +- ⏱ Time: **O(n)** — 各ノヌドをちょうど1回だけ蚪問する +- 💟 Space: **O(h)** — 再垰の呌び出しスタックが朚の高さ分だけ積たれる均衡朚ならO(log n)、最悪の䞀盎線朚でO(n) diff --git a/Algorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/README.md b/Algorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/README.md new file mode 100644 index 0000000..602964f --- /dev/null +++ b/Algorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/README.md @@ -0,0 +1,666 @@ +# Balanced Binary Tree — ボトムアップDFSで O(n) 刀定 + +

目次

+ +- [抂芁](#overview) +- [アルゎリズム芁点TL;DR](#tldr) +- [図解](#figures) +- [正しさのスケッチ](#correctness) +- [蚈算量](#complexity) +- [Python 実装](#impl) +- [CPython最適化ポむント](#cpython) +- [゚ッゞケヌスず怜蚌芳点](#edgecases) +- [FAQ](#faq) + +--- + +

抂芁

+ +> 💡 **この問題を䞀蚀で蚀うず**「朚のすべおのノヌドで、巊右の枝の深さの差が1以内かどうかを刀定する問題」です。 + +䞎えられた二分朚が **高さ均衡height-balanced** かどうかを `True`/`False` で返したす。高さ均衡ずは、**すべおのノヌドにおいお**巊サブツリヌの高さず右サブツリヌの高さの差が最倧1であるこずを指したす。 + +``` +入力: root = [3, 9, 20, null, null, 15, 7] +出力: True + +入力: root = [1, 2, 2, 3, 3, null, null, 4, 4] +出力: False + +入力: root = [] +出力: True +``` + +**なぜ難しいのか**「党ノヌドで差が1以内」ずいう条件は、根ノヌドだけでなく**葉に至るたですべおのノヌドで成立**しなければなりたせん。玠朎に「高さを蚈算しおから均衡を確認する」アプロヌチを取るず、同じノヌドを䜕床も蚪問しおしたい O(n²) になりたす。これを O(n) に改善するには、「高さ蚈算」ず「均衡チェック」を**1パスで同時に行う**蚭蚈が必芁です。 + +**制玄** + +- ノヌド数`0 ≀ n ≀ 5000` +- ノヌド倀`-10^4 ≀ Node.val ≀ 10^4` + +> 📖 **この章で登堎した甚語** +> +> - **高さ均衡height-balanced**朚の党ノヌドで、巊右の郚分朚の高さの差が最倧1であるずいう性質 +> - **サブツリヌ郚分朚**あるノヌドを根ずしお、そこから䞋のすべおのノヌドの集合 +> - **葉ノヌドleaf node**子ノヌドを持たない末端のノヌド +> - **制玄**入力ずしお䞎えられる倀の範囲や条件のこず + +--- + +

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

+ +> 💡 **TL;DRToo Long; Didn't Read**ずは「長くお読めない人向けの芁玄」ずいう意味の略語です。ここではアルゎリズム党䜓の戊略をたずめたす。「なんずなくこういう手順で解くんだな」ずいうむメヌゞを掎むための章です。 + +- **手法**ボトムアップDFS深さ優先探玢 番兵倀 `-1` + - 葉ノヌドから根ノヌドに向かっお「高さ」を積み䞊げながら、同時に均衡チェックを行いたす。䞍均衡が確定した時点で番兵倀 `-1` を䞊䜍ノヌドぞ返すこずで、無駄な探玢を打ち切りたす。 +- **デヌタ構造**`TreeNode` ぞの参照のみ。远加のリストや蟞曞は䞍芁です。 + - 再垰のコヌルスタック関数呌び出しが積み重なるメモリ領域が唯䞀の远加メモリです。 +- **時間蚈算量**`O(n)` — 各ノヌドをちょうど1回だけ蚪問したす。 +- **空間蚈算量**`O(h)` — `h` は朚の高さ。均衡朚なら `O(log n)`、䞀盎線の朚最悪なら `O(n)`。 +- **番兵倀パタヌン**高さは垞に `≥ 0` なので、`-1` を「䞍均衡が怜知枈み」ずいう特別な信号ずしお䜿いたす。 + - これにより「高さを返す関数」ず「均衡チェックを行う関数」を1぀の関数にたずめられたす。 + +> 📖 **この章で登堎した甚語** +> +> - **DFS深さ優先探玢 / Depth-First Search**朚やグラフを「できるだけ深く進んでから戻る」方匏で探玢するアルゎリズム +> - **ボトムアップ**葉ノヌド末端から根ノヌドに向かっお結果を積み䞊げおいく凊理の方向 +> - **番兵倀Sentinel Value**通垞の倀ずしおあり埗ない特別な倀を䜿っお゚ラヌや特殊状態を衚す手法 +> - **コヌルスタックCall Stack**関数呌び出しが積み重なっおいく蚘録。再垰が深くなるほど倧きくなる + +--- + +

図解

+ +> 💡 **Mermaidフロヌチャヌトの読み方**ひし圢 `{}` は「条件分岐」はい/いいえの分かれ道、長方圢 `[]` は「凊理ステップ」を衚したす。矢印のラベル`Yes` / `No`が凊理の流れを瀺したす。 + +## フロヌチャヌト + +以䞋の図は `check_height(node)` 関数の凊理の流れを衚しおいたす。䞊から䞋ぞ読み進めおください。`check_height` は `isBalanced` の内郚で呌ばれ、結果高さ たたは `-1`を根ノヌドたで積み䞊げおいきたす。 + +```mermaid +flowchart TD + Start[Start check_height node] + Start --> BaseCheck{node is None} + BaseCheck -- Yes --> Ret0[return 0] + BaseCheck -- No --> LeftCall[left_h = check_height node.left] + LeftCall --> LeftCheck{left_h == -1} + LeftCheck -- Yes --> RetN1a[return -1] + LeftCheck -- No --> RightCall[right_h = check_height node.right] + RightCall --> RightCheck{right_h == -1} + RightCheck -- Yes --> RetN1b[return -1] + RightCheck -- No --> BalCheck{abs left_h - right_h gt 1} + BalCheck -- Yes --> RetN1c[return -1] + BalCheck -- No --> RetH[return max left_h right_h + 1] +``` + +**䞻芁なノヌドの意味** + +- `Start[Start check_height node]``check_height` が呌ばれた入り口。匕数 `node` は珟圚凊理䞭のノヌド +- `BaseCheck{node is None}`朚の末端これ以䞊子がないかを刀定する条件分岐 +- `Ret0[return 0]`空のノヌドは「高さ0の朚」なので 0 を返すベヌスケヌス +- `LeftCheck{left_h == -1}`巊サブツリヌで䞍均衡が怜知枈みかを刀定する早期リタヌン +- `BalCheck{abs left_h - right_h gt 1}`このノヌドで巊右の高さの差が倧きすぎるかを刀定 +- `RetN1c[return -1]`番兵倀 `-1` を返しお「䞍均衡」を䞊䜍ノヌドぞ䌝播させる +- `RetH[return max left_h right_h + 1]`均衡OKのノヌドは「自分の高さ」を返しお䞊䜍ぞ報告 + +--- + +### デヌタフロヌ図 + +以䞋の図は、入力ツリヌがどのように凊理されお最終的な `True`/`False` が埗られるかを瀺しおいたす。 + +```mermaid +graph LR + subgraph Input + A[TreeNode root] + end + subgraph Core + A --> B[check_height root] + B --> C[check_height left subtree] + B --> D[check_height right subtree] + C --> E[height or -1] + D --> F[height or -1] + E --> G[combine at node] + F --> G + G --> H[propagate up] + end + subgraph Output + H --> I{result != -1} + I -- True --> J[return True balanced] + I -- False --> K[return False unbalanced] + end +``` + +**䞻芁な流れの説明** + +- `Input → check_height root`ルヌトノヌドから再垰が始たる +- `check_height → left/right subtree`巊右のサブツリヌを再垰的に凊理する +- `height or -1 → combine at node`巊右の結果を受け取り、このノヌドでの均衡を刀定する +- `propagate up`結果高さ たたは `-1`を芪ノヌドぞ返しおいく +- `result != -1 → True/False`最終的な刀定を行う + +--- + +💡 **代衚䟋 `root = [3, 9, 20, null, null, 15, 7]` でのトレヌス** + +> + +``` +Step 1: check_height(3) 開始 + +Step 2: check_height(9) を呌ぶnode=3 の巊 + check_height(None) → 0 9の巊 + check_height(None) → 0 9の右 + abs(0-0) = 0 ≀ 1 → 均衡OK + return max(0,0) + 1 = 1 + → left_h = 1 node=3 にずっお + +Step 3: check_height(20) を呌ぶnode=3 の右 + check_height(15) → 1 None + None から + check_height(7) → 1 None + None から + abs(1-1) = 0 ≀ 1 → 均衡OK + return max(1,1) + 1 = 2 + → right_h = 2 node=3 にずっお + +Step 4: node=3 での均衡チェック + abs(1-2) = 1 ≀ 1 → 均衡OKぎりぎり均衡 + return max(1,2) + 1 = 3 + +Step 5: isBalanced → 3 != -1 → True ✅ +``` + +> 📖 **この章で登堎した甚語** +> +> - **フロヌチャヌト**凊理の手順を図圢ず矢印で衚したもの。ひし圢=条件分岐、長方圢=凊理 +> - **デヌタフロヌ図**デヌタがどのように倉換・移動するかを瀺す図 +> - **䌝播propagate**ある倀や信号が䞋䜍から䞊䜍ぞたたは逆に次々ず枡されおいくこず + +--- + +

正しさのスケッチ

+ +> 💡 **「正しさのスケッチ」**ずは、アルゎリズムが**垞に正しい答えを返すこずの根拠**を敎理したものです。数孊的な厳密蚌明ではなく「なぜ正しいず蚀えるか」を盎感的に説明したす。 + +### 䞍倉条件アルゎリズムが正しく動くために、凊理䞭ずっず成り立ち続けるべき条件 + +`check_height(node)` が返す倀は、垞に以䞋のどちらかです + +1. `node` を根ずするサブツリヌが均衡しおいる堎合 → そのサブツリヌの正確な高さ`≥ 0` +2. `node` を根ずするサブツリヌが䞍均衡の堎合 → 番兵倀 `-1` + +この䞍倉条件が成立する理由 + +- 高さは「子の高さの最倧倀 + 1」で定矩されるため、ベヌスケヌス高さ0から垰玍的に正しい倀が積み䞊がりたす +- `-1` は通垞の高さずしお絶察に珟れない倀高さは垞に `≥ 0`なので、信号ずしお安党に䜿えたす + +### 網矅性すべおのケヌスをもれなく凊理できおいるずいう保蚌 + +`check_height` は以䞋の4パタヌンをすべおカバヌしおいたす + +| 状況 | 条件 | 凊理 | +| -------------------- | --------------------------- | --------------------------------- | +| 末端ノヌドに到達 | `node is None` | `return 0` | +| 巊サブツリヌが䞍均衡 | `left_h == -1` | `return -1`早期リタヌン | +| 右サブツリヌが䞍均衡 | `right_h == -1` | `return -1`早期リタヌン | +| このノヌドで䞍均衡 | `abs(left_h - right_h) > 1` | `return -1` | +| 均衡しおいる | 䞊蚘以倖 | `return max(left_h, right_h) + 1` | + +### ベヌスケヌス再垰の終了条件 + +`node is None` のずき `return 0` を返したす。これは「空の朚の高さは0」ずいう定矩ず䞀臎したす。空の朚は高さの差を蚈算するノヌドが存圚しないため、定矩䞊「均衡しおいる」ず蚀えたす`0 != -1` なので `True` を返す。 + +### 終了性アルゎリズムが必ず有限ステップで終わるずいう保蚌 + +`check_height` の再垰呌び出しは毎回 `node.left` たたは `node.right` を枡したす。二分朚は有限個のノヌドを持ち、各呌び出しで必ず「深さが1増える」ため、有限ステップで `None`葉の䞋に到達したす。埪環参照は二分朚の定矩䞊存圚しないため、無限ルヌプは発生したせん。 + +> 📖 **この章で登堎した甚語** +> +> - **䞍倉条件Invariant**アルゎリズムが正しく動くために、凊理䞭ずっず成り立ち続けるべき条件 +> - **網矅性Completeness**すべおのケヌスをもれなく凊理できおいるずいう保蚌 +> - **ベヌスケヌスBase Case**再垰の終了条件。これがないず無限再垰になる +> - **終了性Termination**アルゎリズムが必ず有限ステップで終わるずいう保蚌 +> - **垰玍的Inductive**小さいケヌスが正しければ、より倧きいケヌスも正しいずいう論法 + +--- + +

蚈算量

+ +> 💡 **蚈算量**ずは「入力が倧きくなるに぀れお、凊理にかかる時間・メモリがどう増えるか」の目安です。 + +| 蚘法 | 意味 | 盎感的なむメヌゞ | +| ---------- | ---------------------- | -------------------------- | +| `O(1)` | 入力サむズによらず䞀定 | 蟞曞で盎接ペヌゞを開く | +| `O(log n)` | 入力の察数で増加 | 蟞曞を二分探玢で匕く | +| `O(n)` | 入力に比䟋しお増加 | リストを端から順に読む | +| `O(n²)` | 入力の2乗で増加 | 党ペアを総圓たりで確認する | + +### このアルゎリズムの蚈算量 + +| | 蚈算量 | 理由 | +| -------- | ------ | ------------------------------------------------------------------------------------------------------------ | +| **時間** | `O(n)` | `check_height` は各ノヌドをちょうど1回だけ蚪問する。早期リタヌンにより䞍均衡が確定した先のノヌドは蚪問しない | +| **空間** | `O(h)` | 再垰のコヌルスタックが朚の高さ `h` 分だけ積み重なる | + +`h` の具䜓的な倀 + +- **均衡朚**AVL朚など`h = O(log n)` → 空間 `O(log n)` +- **最悪ケヌス**䞀盎線の朚`h = O(n)` → 空間 `O(n)` + +### 玠朎な実装トップダりンずの比范 + +| アプロヌチ | 時間蚈算量 | 空間蚈算量 | 備考 | +| ----------------------------- | ---------- | ---------- | --------------------------------------------------------- | +| **ボトムアップDFS本実装** | `O(n)` | `O(h)` | 1パス。各ノヌドを1回だけ蚪問 | +| トップダりン再垰玠朎 | `O(n²)` | `O(h)` | `height()` ず `isBalanced()` を分離するため二重蚪問が発生 | +| BFS幅優先探玢 | `O(n)` | `O(n)` | `deque` の確保コストがある。実装も耇雑 | + +**なぜトップダりンが O(n²) になるのか**トップダりンでは「たず根での高さ差を確認 → 巊右の子での高さ差を確認 → ...」ず繰り返すため、深い郚分のノヌドは繰り返し `height()` の蚈算察象になりたす。n 段の朚では最悪 `1 + 2 + ... + n = O(n²)` の蚪問回数になりたす。 + +> 📖 **この章で登堎した甚語** +> +> - **時間蚈算量Time Complexity**入力の倧きさに察しお凊理にかかる手間がどう増えるかの目安 +> - **空間蚈算量Space Complexity**凊理䞭に䜿うメモリ量がどう増えるかの目安 +> - **トップダりンTop-Down**根ノヌドから葉ノヌドに向かっお凊理する方向 +> - **コヌルスタックCall Stack**関数呌び出しが積み重なっおいく蚘録領域 + +--- + +

Python 実装

+ +> 💡 **コヌドを読む前に、実装の党䜓的な骚栌を確認したしょう。** +> +> 1. `isBalanced` が倖郚に公開する゚ントリポむント。内郚で `check_height` を呌ぶ +> 2. `check_height` をネスト関数関数の䞭の関数ずしお定矩するこずで内郚実装を隠す +> 3. ベヌスケヌス`node is None`を最初にチェックし `0` を返す +> 4. 巊右のサブツリヌを再垰的に凊理し、`-1` が返っおきたら即座に `return -1`早期リタヌン +> 5. `abs(left_h - right_h) > 1` で均衡チェックを行い、OKなら `max(left_h, right_h) + 1` を返す +> 6. `isBalanced` は `check_height(root) != -1` を返す + +```python +from __future__ import annotations +# from __future__ import annotations型ヒントを文字列ずしお扱うようにする宣蚀。 +# Python 3.10 以前でも `TreeNode | None` のような蚘法を䜿えるようにするため。 + +from typing import Optional, TYPE_CHECKING + +if TYPE_CHECKING: + # TYPE_CHECKING ブロックpylance型チェッカヌのためだけに読たれる宣蚀。 + # 実行時には読み蟌たれないため、TreeNode が未定矩でも゚ラヌにならない。 + class TreeNode: + val: int + left: Optional[TreeNode] + right: Optional[TreeNode] + def __init__( + self, + val: int = 0, + left: Optional[TreeNode] = None, + right: Optional[TreeNode] = None, + ) -> None: ... + +# LeetCode の実行環境では TreeNode は事前に定矩されおいる。 +# ロヌカルで動かすずきのフォヌルバック定矩。 +try: + TreeNode # 既に定矩されおいればこのブロックはスキップ +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 = val + self.left = left + self.right = right + + +class Solution: + def isBalanced(self, root: Optional[TreeNode]) -> bool: + """ + 二分朚が高さ均衡かどうかを刀定する。 + + ボトムアップDFS + 番兵倀パタヌンで O(n) を実珟する。 + + Args: + root: 二分朚のルヌトノヌド。空の朚の堎合は None。 + + Returns: + すべおのノヌドで巊右の高さの差が 1 以内なら True、そうでなければ False。 + """ + + def check_height(node: Optional[TreeNode]) -> int: + """ + サブツリヌの高さを返す。䞍均衡が怜出された堎合は -1 を返す。 + + なぜネスト関数にするか + 倖郚から盎接呌べないようにし、「-1 ずいう番兵倀を返す」ずいう + 内郚の詳现を isBalanced の呌び出し元に芋せないようにするため。 + たた、ネスト関数はロヌカルスコヌプで名前解決されるため、 + クラスメ゜ッドより少し高速CPythonの名前解決の仕組みによる。 + + Args: + node: 珟圚凊理䞭のノヌドNone = 朚の末端 + + Returns: + 均衡しおいる堎合は 0 以䞊の高さ、䞍均衡なら -1。 + """ + + # ── ベヌスケヌス ──────────────────────────────────────────── + # node is None を䜿う理由 + # Python の None はシングルトンプログラム䞭に1぀しか存圚しないオブゞェクト。 + # `is` は「同じオブゞェクトかどうか」を確認するため、 + # `== None` より意味的に正確で高速。PEP 8Pythonの公匏スタむルガむドでも掚奚。 + if node is None: + # 空の朚ノヌドなしの高さは 0。 + # この 0 が芪ノヌドの left_h たたは right_h ずしお䜿われる。 + return 0 + + # ── 巊サブツリヌを再垰的に怜査 ────────────────────────────── + # node.left は Optional[TreeNode] 型TreeNode か None のどちらか。 + # None のずきは次の再垰呌び出しでベヌスケヌスずしお凊理される。 + left_h: int = check_height(node.left) + + # 早期リタヌンEarly Return + # 巊で䞍均衡が確定しおいれば、右サブツリヌを調べる必芁が党くない。 + # これにより䞍必芁な再垰呌び出しを省き、効率を保぀。 + if left_h == -1: + return -1 + + # ── 右サブツリヌを再垰的に怜査 ────────────────────────────── + right_h: int = check_height(node.right) + + # 右サブツリヌで䞍均衡が怜知枈みのずきも、-1 を䞊䜍ぞ䌝播させる。 + if right_h == -1: + return -1 + + # ── このノヌドでの均衡チェック ─────────────────────────────── + # abs() を䜿う理由 + # 「巊が深い」「右が深い」の䞡パタヌンを1行で凊理でき、 + # か぀ abs() はCPythonのC実装組み蟌み関数なので高速。 + if abs(left_h - right_h) > 1: + # このノヌドで䞍均衡 → 番兵倀 -1 を返しお䞍均衡を䞊䜍ぞ知らせる + return -1 + + # ── このノヌドの高さを返す ──────────────────────────────────── + # このノヌドの高さ = 巊右の最倧倀 + 自分自身の1段分。 + # +1 を忘れるず高さが1ずれお正しい均衡チェックができなくなる。 + # max() もCPythonのC実装で高速。 + return max(left_h, right_h) + 1 + + # check_height(root) が -1 でなければ、党ノヌドが均衡しおいる。 + # -1 でないTrue = 均衡、-1False = 䞍均衡。 + return check_height(root) != -1 +``` + +--- + +💡 **コヌドの動䜜トレヌス**代衚䟋 `root = [3, 9, 20, null, null, 15, 7]` + +``` +isBalanced(root) 呌び出し + → check_height(node=TreeNode(3)) 開始 + + ├─ check_height(node=TreeNode(9)) ← 3の巊 + │ ├─ check_height(None) → return 0 ← 9の巊 + │ │ left_h=0; (0 != -1) → 継続 + │ ├─ check_height(None) → return 0 ← 9の右 + │ │ right_h=0; (0 != -1) → 継続 + │ ├─ abs(0-0) = 0 ≀ 1 → 均衡OK + │ └─ return max(0,0)+1 = 1 + │ + │ left_h = 1; (1 != -1) → 継続 + │ + ├─ check_height(node=TreeNode(20)) ← 3の右 + │ ├─ check_height(TreeNode(15)) → return 1 ← 同様の手順 + │ │ left_h=1; (1 != -1) → 継続 + │ ├─ check_height(TreeNode(7)) → return 1 + │ │ right_h=1; (1 != -1) → 継続 + │ ├─ abs(1-1) = 0 ≀ 1 → 均衡OK + │ └─ return max(1,1)+1 = 2 + │ + │ right_h = 2; (2 != -1) → 継続 + │ + ├─ abs(1-2) = 1 ≀ 1 → 均衡OKぎりぎり均衡 + └─ return max(1,2)+1 = 3 + +check_height(root) = 3 +3 != -1 → isBalanced = True ✅ +``` + +**䞍均衡ケヌス** `root = [1, 2, 2, 3, 3, null, null, 4, 4]`抜粋 + +``` + check_height(TreeNode(1)) ← ルヌト + left_h = check_height(2の巊) = 3 深い + right_h = check_height(2の右) = 1 + abs(3-1) = 2 > 1 → 䞍均衡 + return -1 + + check_height(root) = -1 + -1 == -1 → isBalanced = False ✅ +``` + +> 📖 **この章で登堎した甚語** +> +> - **`from __future__ import annotations`**型ヒントを文字列ずしお扱うようにする宣蚀。前方参照の問題を回避できる +> - **`TYPE_CHECKING`**`True` になるのは型チェッカヌpylance等が解析するずきだけ。実行時は `False` +> - **`Optional[X]`**`X` たたは `None` のどちらかであるこずを衚す型ヒント。`X | None` ず同矩Python 3.10+ +> - **`__slots__`**クラスの属性をあらかじめ宣蚀し、蟞曞の代わりにスロットで管理する機胜 +> - **ネスト関数Nested Function**関数の䞭に定矩された関数。倖郚スコヌプから盎接呌べない +> - **早期リタヌンEarly Return**条件が確定した時点で即座に `return` する手法。ネストを浅く保おる + +--- + +

CPython最適化ポむント

+ +> 💡 この章では「同じ凊理でも曞き方によっお速さが倉わる理由」を説明したす。最適化テクニックは「最適化前 → 最適化埌 → なぜ速いか」の3点セットで説明したす。 + +### 最適化1`is None` vs `== None` + +```python +# 最適化前遅い・意味的にも䞍正確 +if node == None: + return 0 + +# 最適化埌速い・PEP 8 掚奚 +if node is None: + return 0 +``` + +**なぜ速いか**`== None` は `__eq__` メ゜ッドを呌び出すため関数呌び出しのオヌバヌヘッドがありたす。䞀方 `is` は「同じオブゞェクトかどうか」をポむンタメモリアドレスの比范だけで刀断するため、C レベルで1呜什で完了したす。`None` は Python のシングルトンなので `is` が意味的にも正確です。 + +--- + +### 最適化2組み蟌み関数 `abs()` ず `max()` の掻甚 + +```python +# 最適化前Pure Python の条件分岐 +if left_h > right_h: + diff = left_h - right_h +else: + diff = right_h - left_h +if diff > 1: + return -1 + +# 最適化埌C実装の組み蟌み関数を䜿う +if abs(left_h - right_h) > 1: + return -1 +``` + +**なぜ速いか**`abs()` ず `max()` はCPythonのC実装組み蟌み関数であり、Pure PythonPythonコヌドで曞かれた凊理より高速に動䜜したす。たたコヌドが簡朔になり「巊が深い」「右が深い」の䞡パタヌンを1行で凊理できたす。 + +```python +# 最終的な高さの蚈算も max() を䜿う同様の理由 +return max(left_h, right_h) + 1 +``` + +--- + +### 最適化3ネスト関数でのロヌカルスコヌプ掻甚 + +```python +# 最適化前クラスメ゜ッドずしお定矩 +class Solution: + def check_height(self, node): # self 経由のアクセスで蟞曞怜玢が発生 + ... + def isBalanced(self, root): + return self.check_height(root) != -1 + +# 最適化埌ネスト関数ずしお定矩 +class Solution: + def isBalanced(self, root): + def check_height(node): # ロヌカルスコヌプで名前解決 → 高速 + ... + return check_height(root) != -1 +``` + +**なぜ速いか**Pythonの名前解決は「ロヌカル → ゚ンクロヌゞング → グロヌバル → 組み蟌み」の順に探玢したすLEGB ルヌル。ネスト関数ぱンクロヌゞングスコヌプで芋぀かるため、`self.check_height` のようにグロヌバルスコヌプ経由で蟞曞怜玢するより高速です。 + +--- + +### 最適化4早期リタヌンによる枝刈り + +```python +# 最適化なし䞡サブツリヌを必ず蚈算する +left_h = check_height(node.left) +right_h = check_height(node.right) +if left_h == -1 or right_h == -1: + return -1 + +# 最適化あり巊で䞍均衡が確定したら右を調べない +left_h = check_height(node.left) +if left_h == -1: + return -1 # ← ここで右サブツリヌの探玢をスキップ +right_h = check_height(node.right) +``` + +**なぜ速いか**䞍均衡が巊サブツリヌで確定した時点で、右サブツリヌの探玢は結果に圱響したせん。早期リタヌン枝刈り答えが埗られないず分かった探玢経路を途䞭で切り捚おるこずにより、最悪ケヌスに近い朚での探玢コストを倧幅に削枛できたす。 + +> 📖 **この章で登堎した甚語** +> +> - **LEGB ルヌル**Python の名前解決の優先順䜍。Localロヌカル→ Enclosing゚ンクロヌゞング→ Globalグロヌバル→ Built-in組み蟌みの順 +> - **C実装の組み蟌み関数**`abs()` `max()` `len()` など、Pythonコヌドではなく C 蚀語で実装された関数。オヌバヌヘッドが少なく高速 +> - **枝刈りPruning**答えが埗られないず分かった探玢経路を途䞭で切り捚おるこず。探玢空間を削枛できる +> - **シングルトンSingleton**プログラム䞭に1぀しか存圚しないオブゞェクト。Python の `None`・`True`・`False` がこれにあたる + +--- + +

゚ッゞケヌスず怜蚌芳点

+ +> 💡 **゚ッゞケヌス**ずは「入力が空・最小倀・最倧倀・特殊な圢状」など、通垞ずは異なる境界的な入力のこずです。゚ッゞケヌスを芋萜ずすず、普通のテストは通るのに特定の入力でだけバグが発生したす。 + +| # | ゚ッゞケヌス | 入力䟋 | 期埅出力 | なぜ問題になりうるか | +| --- | -------------------------------- | ----------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1 | **空の朚** | `root = None` | `True` | ベヌスケヌスで即座に `0` を返すため、`check_height(None) = 0 != -1 → True` になるこずを確認 | +| 2 | **ノヌド1個** | `root = [1]` | `True` | 巊右ずもに `None` → `abs(0-0) = 0 ≀ 1` → 均衡 | +| 3 | **片偎にのみ子がある右傟き** | `root = [1, None, 2, None, 3]` | `False` | 高さの差が `abs(0-2) = 2 > 1` ずなるため䞍均衡。`[1, None, 2]` の堎合は `abs(0-1) = 1` で均衡`True`ずなる。 | +| 4 | **䞀盎線の朚最悪ケヌス** | `[1, 2, null, 3, null, 4, ...]` n=5000 | `False` | 再垰の深さが n=5000 に達する。LeetCodeの Python 環境は再垰䞊限が匕き䞊げられおいるが、ロヌカルでは `sys.setrecursionlimit()` が必芁になる堎合がある | +| 5 | **完党二分朚** | n=5000 の完党二分朚 | `True` | すべおのノヌドで `abs(h_left - h_right) ≀ 1` が成立。高さは `O(log n)` | +| 6 | **根のみ䞍均衡・子は均衡** | `[1, 2, None, 3, 4]` | `False` | 子ノヌドが均衡でも根ノヌドで `abs(2-0) = 2 > 1` → 䞍均衡 | +| 7 | **根は均衡・深いずころで䞍均衡** | `[1, 2, 2, 3, null, null, 3, 4, null, null, 4]` | `False` | 根でのチェックを通過しおも、深いノヌドで䞍均衡が怜知されるず `-1` が䌝播する | +| 8 | **ノヌド倀が境界倀** | ノヌド倀 = `-10^4` や `10^4` | 正垞動䜜 | `val` は均衡チェックに圱響しないため、倀の倧小は結果に無関係 | + +> 📖 **この章で登堎した甚語** +> +> - **゚ッゞケヌスEdge Case**空のリスト・芁玠1぀・最倧サむズ入力など、境界的な条件の入力 +> - **完党二分朚Complete Binary Tree**最埌の段を陀く党段が埋たっおおり、最埌の段は巊から詰たっおいる二分朚 +> - **再垰䞊限Recursion Limit**Python が蚱可する最倧の再垰深さ。デフォルトは 1000。`sys.setrecursionlimit()` で倉曎できる + +--- + +

FAQ

+ +> 💡 **FAQFrequently Asked Questions**は「初孊者が぀たずきやすいポむント」を想定した質問ず回答です。各回答は「結論 → 理由 → 補足具䜓䟋」の順で曞かれおいたす。 + +--- + +**Q1. なぜ番兵倀ずしお `-1` を䜿うのですか `False` を䜿えばよいのでは** + +**結論**`-1` を䜿うのは、「高さを返す」ず「䞍均衡を䌝える」の2぀の圹割を1぀の関数でこなすためです。 + +**理由**`False` を返すず型が `bool` になり、「高さ`int`」ず「䞍均衡フラグ`bool`」の2皮類が混圚しお型安党でなくなりたす。`-1` は「高さは垞に `≥ 0`」ずいう性質を利甚した安党な番兵倀で、型を `int` 䞀皮類に保おたす。 + +**補足**䟋えば `return (height, is_balanced)` のようにタプルで返すこずもできたすが、タプルの生成コストが発生したす。`-1` を䜿う実装は最もシンプルで高速です。 + +--- + +**Q2. トップダりン再垰玠朎な方法がなぜ O(n²) になるのか、具䜓䟋で教えおください。** + +**結論**トップダりンでは「高さ蚈算」ず「均衡チェック」を別々に行うため、同じノヌドが耇数回 `height()` の蚈算察象になりたす。 + +**理由**以䞋の朚を䟋に考えたす。 + +``` + 1 + / \ + 2 3 + / \ + 4 5 +``` + +トップダりンで `isBalanced(1)` を呌ぶず + +1. `height(2)` ず `height(3)` を蚈算4, 5 を蚪問 +2. `isBalanced(2)` を再垰呌び出し → たた `height(4)` ず `height(5)` を蚈算二重蚪問 +3. `isBalanced(3)` を再垰呌び出し → たた `height()` を蚈算 + +**補足**䞀盎線の朚n 段では、最深ノヌドが `1 + 2 + ... + n = n(n+1)/2 = O(n²)` 回蚪問されたす。 + +--- + +**Q3. `node is None` ず `not node` はどちらが良いですか** + +**結論**`node is None` の方が掚奚されたす。 + +**理由**`not node` は「`node` がFalsy停ず評䟡される倀かどうか」を刀定したす。`None` はFalsyですが、`0`・`[]`・`""` もFalsyです。もし `TreeNode` が `__bool__` を実装しおいお特定の条件で `False` を返す堎合、`not node` は意図しない動䜜をする可胜性がありたす。`node is None` は「None ず同じオブゞェクトかどうか」だけを確認するため、垞に意図通りに動䜜したす。 + +**補足**PEP 8Pythonの公匏コヌディングスタむルガむドでも `None` ずの比范には `is` / `is not` を䜿うこずが明瀺されおいたす。 + +--- + +**Q4. 再垰ではなくむテレヌティブ繰り返し凊理で実装できたすか** + +**結論**できたす。ただし実装が倧幅に耇雑になりたす。 + +**理由**再垰はコヌルスタックを暗黙的に利甚したすが、むテレヌティブ実装では自分でスタック`deque` などを管理し、「埌凊理」子ノヌドを凊理しおから芪を凊理する埌順DFSを明瀺的に実装する必芁がありたす。 + +**補足むテレヌティブの骚栌** + +```python +from collections import deque + +stack: deque = deque() +heights: dict = {} +# ... post-order traversal を手動で実装する耇雑 +``` + +ノヌド数 n が最倧 5000 ずいう制玄のもずでは、再垰の深さが問題になりにくいため、再垰実装の方がシンプルで保守性が高いです。 + +--- + +**Q5. `check_height` を `Solution` のメ゜ッドずしお定矩するのず、ネスト関数にするのでは䜕が違いたすか** + +**結論**ネスト関数の方が「情報隠蔜」ず「わずかな速床向䞊」の2点で優れおいたす。 + +**理由** + +- **情報隠蔜**`check_height` は「-1 ずいう番兵倀を返す内郚実装」です。クラスメ゜ッドにするず `solution.check_height(node)` ずしお倖郚から呌べおしたい、番兵倀パタヌンの内郚実装が挏れたす。ネスト関数にするず `isBalanced` の倖から盎接呌ぶこずができたせん +- **速床**Pythonの名前解決はロヌカルスコヌプが最速ですLEGB ルヌル。ネスト関数ぱンクロヌゞングスコヌプで解決されるため、`self.check_height` のようにグロヌバル蟞曞を経由するより高速です + +**補足**チヌムのコヌディング芏玄やコヌドの芏暡によっおは、クラスメ゜ッドずしお定矩しお `_check_height`アンダヌスコアで「内郚メ゜ッド」を瀺す慣習ずするこずも䞀般的です。 + +> 📖 **この章で登堎した甚語** +> +> - **Falsy停倀**`if` 文で `False` ずしお評䟡される倀。Python では `None`・`0`・`[]`・`""`・`{}` など +> - **埌順DFSPost-order DFS**巊サブツリヌ → 右サブツリヌ → 自分自身 の順に蚪問するDFS。ボトムアップ凊理に察応 +> - **情報隠蔜Information Hiding**内郚実装の詳现を倖郚から芋えないようにするこず。むンタヌフェヌスをシンプルに保぀蚭蚈原則 +> - **PEP 8**Pythonの公匏コヌディングスタむルガむド。呜名芏則・空癜の䜿い方・`is None` の䜿甚など倚くのルヌルを定めおいる + +--- + +_LeetCode 110 — Balanced Binary Tree_ +_アルゎリズムボトムアップDFS + 番兵倀パタヌン | Time: O(n) | Space: O(h)_ diff --git a/Algorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/README_react.html b/Algorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/README_react.html new file mode 100644 index 0000000..e0dd375 --- /dev/null +++ b/Algorithm/BinaryTree/leetcode/110. Balanced Binary Tree/claude sonnet 4.6 adaptive/README_react.html @@ -0,0 +1,1958 @@ + + + + + + LeetCode 110 · Balanced Binary Tree + + + + + + + + + + + + + + + + + +
+ + + + +
+

+ アルゎリズム抂芁 +

+ +
+

+ 💡 + この問題を䞀蚀で蚀うず「朚のすべおのノヌドで、巊右の枝の深さの差が1以内かどうかを刀定する問題」 +

+

+ 高さ均衡二分朚height-balanced binary + treeずは、党ノヌドで巊右の郚分朚の高さの差が最倧1であるような二分朚です。 + 空の朚root = nullも高さ均衡ずしお扱いたす。 +

+
+ +
+

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

+
    +
  • + 「高さ蚈算」ず「均衡チェック」を別々に行うず、同じノヌドを䜕床も蚪問するためO(n²)になっおしたいたす玠朎なトップダりン再垰の眠。 +
  • +
  • + 䞍均衡が芋぀かった瞬間に結果を䞊䜍ノヌドぞ䌝える仕組みがないず、無駄な蚈算が増えおしたいたす。 +
  • +
+
+ +
+
+
O(n)
+
時間蚈算量
+
+
+
O(h)
+
空間蚈算量
+
+
+
+ Bottom-up DFS +
+
手法
+
+
+
+ 番兵倀 -1 +
+
゚ラヌ䌝播
+
+
+ +
+
+
+ Example 1 — true +
+
+    3
+   / \
+  9  20
+     / \
+    15   7
+

+ 党ノヌドで巊右の高さの差 ≀ 1 → + true +

+
+
+
+ Example 2 — false +
+
+      1
+    /   \
+   2     2
+  / \
+ 3   3
+/ \
+4   4
+

+ ルヌトの巊右の高さ差 = 2 → + false +

+
+
+
+ Example 3 — true +
+
+空の朚
+root = null
+

+ 空の朚は定矩䞊 均衡 → + true +

+
+
+ +
+

+ 🧠 解法のアむデア1パスで高さ蚈算ず均衡チェックを同時に行う +

+

+ 葉ノヌド子のないノヌドから根ノヌドに向かっおさかのがりながらボトムアップ、高さを返し぀぀同時に均衡チェックも行いたす。 + 䞍均衡が芋぀かったら + -1番兵倀を返し、䞊䜍ノヌドぞ䌝播させたす。 + これにより各ノヌドをちょうど1回だけ蚪問する O(n) が実珟できたす。 +

+
+
+ + +
+

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

+

+ 各ステップをクリックするか ▶ Play で自動再生できたす。 +

+
+
+ + +
+

+ Python 実装 +

+ +
+

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

+
    +
  1. + isBalanced倖郚に公開する゚ントリポむント。check_height を呌んで -1 でなければ + True を返す +
  2. +
  3. + check_heightネスト関数再垰の本䜓。高さを返し぀぀䞍均衡なら -1 を返す +
  4. +
  5. ベヌスケヌスnode が None なら高さ 0 を返す
  6. +
  7. 巊右を再垰し、-1 が返っおきたら即 -1 を䌝播早期リタヌン
  8. +
  9. + 巊右の高さの差 > 1 なら -1、そうでなければ max(å·Š, 右) + 1 を返す +
  10. +
+
+ +
from typing import Optional
+
+class Solution:
+    def isBalanced(self, root: Optional[TreeNode]) -> bool:
+
+        def check_height(node: Optional[TreeNode]) -> int:
+            # ベヌスケヌス空のノヌドは高さ0
+            # `is None` はPEP 8掚奚。None はシングルトンなので is が正確
+            if node is None:
+                return 0
+
+            # 巊サブツリヌの高さを再垰で取埗
+            left_height = check_height(node.left)
+            # 巊が -1䞍均衡怜知枈みなら即座に -1 を返す早期リタヌン
+            if left_height == -1:
+                return -1
+
+            # 右サブツリヌの高さを再垰で取埗
+            right_height = check_height(node.right)
+            # 右が -1 のずきも同様に䌝播
+            if right_height == -1:
+                return -1
+
+            # このノヌドでの均衡チェック
+            # abs() はC実装の組み蟌み関数で高速
+            if abs(left_height - right_height) > 1:
+                return -1  # 番兵倀 -1 を返しお䞍均衡を䞊䜍ぞ知らせる
+
+            # このノヌドの高さ = max(å·Š, 右) + 自分の1
+            # max() もC実装の組み蟌み関数で高速
+            return max(left_height, right_height) + 1
+
+        # check_height が -1 でなければ均衡しおいる
+        return check_height(root) != -1
+ +
+

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

+
+check_height(3)  開始
+  ├─ check_height(9)   → left=0, right=0, diff=0 ≀ 1  → return 1
+  │   left_height=1 (≠-1、継続)
+  ├─ check_height(20)  開始
+  │   ├─ check_height(15) → return 1
+  │   │   left_height=1 (≠-1、継続)
+  │   ├─ check_height(7)  → return 1
+  │   │   right_height=1 (≠-1、継続)
+  │   └─ abs(1-1)=0 ≀ 1 → return max(1,1)+1 = 2
+  │   right_height=2 (≠-1、継続)
+  └─ abs(1-2)=1 ≀ 1 → return max(1,2)+1 = 3
+
+check_height(root) = 3
+3 != -1  →  isBalanced = True ✅
+
+ +
+

+ ▶ 䞍均衡ケヌス [1,2,2,3,3,null,null,4,4] での動䜜トレヌス +

+
+check_height(4) → 1  (巊の4)
+check_height(4) → 1  (右の4)
+check_height(3) [å·Š]  → abs(1-1)=0 → return 2
+check_height(3) [右]  → abs(0-0)=0 → return 1
+check_height(2) [å·Š]  → abs(2-1)=1 ≀ 1 → return 3
+check_height(2) [右]  → return 1
+check_height(1) [ルヌト]
+  left_height=3, right_height=1
+  abs(3-1) = 2  > 1  → return -1  ← 䞍均衡
+
+check_height(root) = -1
+-1 == -1  →  isBalanced = False ✅
+
+
+ + +
+

+ 凊理フロヌチャヌト +

+ +
+

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

+
+
+ + + + 楕円緑 開始・終了 +
+
+ + + + 四角青 凊理ステップ +
+
+ + + + ひし圢黄 条件分岐 +
+
+ 緑はい + 赀いいえ +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + isBalanced(root) 開始 + + + check_height(root) を呌ぶ + + + + + + + + + check_height(node) を呌ぶ + + + node = 珟圚凊理䞭のノヌド + + + + + + + + + node is None ? + + + 朚の末端に到達したか + + + + + + はい + + + + return + + + 0 + + + + + + いいえ + + + + + + left_height = check_height(node.left) + + + 巊の郚分朚の高さを再垰で蚈算 + + + + + + + + + left_height == -1 ? + + + 巊サブツリヌで䞍均衡を怜知枈みか + + + + + + はい + + + + return + + + -1 + + + + + + いいえ + + + + + + right_height = check_height(node.right) + + + 右の郚分朚の高さを再垰で蚈算 + + + + + + + + + right_height == -1 ? + + + 右サブツリヌで䞍均衡を怜知枈みか + + + + + + はい + + + + return + + + -1 + + + + + + いいえ + + + + + + abs(left_height - right_height) > 1 ? + + + このノヌドで巊右の高さの差が倧きすぎるか + + + + + + はい + + + + return + + + -1 + + + + + + いいえ + + + + + + return max(left_height, right_height) + 1 + + + このノヌドの高さ均衡OKを芪ぞ返す + + + + + + + + + check_height(root) != -1 を返す + + + True均衡たたは False䞍均衡 + + +
+ +
+

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

+
    +
  1. + 「開始」→ check_height(node=3) を呌ぶ。node は None でないので凊理継続 +
  2. +
  3. + 巊サブツリヌ check_height(9) を蚈算 → 9の巊右はどちらも None + なので高さ1を返す。-1 でないので継続 +
  4. +
  5. + 右サブツリヌ check_height(20) を蚈算 → 15ず7の高さがそれぞれ1 → + abs(1-1)=0 ≀ 1 → 高さ2を返す。-1 でないので継続 +
  6. +
  7. ルヌト3での均衡チェックabs(1-2)=1 ≀ 1 → 均衡OK → 高さ3を返す
  8. +
  9. + 「終了」→ 3 != -1 → isBalanced = + True +
  10. +
+
+
+ + +
+

+ 蚈算量分析 +

+ +
+

+ 📖 Big-O 蚘法の読み方n = + ノヌド数が倧きくなるに぀れお凊理時間がどう増えるかの目安 +

+
+
+
O(1)
+
+ 垞に䞀定
䟋蟞曞の盎接匕き +
+
+
+
O(n)
+
+ 入力に比䟋
䟋リストを1回走査 +
+
+
+
O(log n)
+
+ log倍に増加
䟋二分探玢 +
+
+
+
O(n²)
+
+ 入力の2乗
䟋二重ルヌプ総圓たり +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ アプロヌチ + + 時間蚈算量 + + 空間蚈算量 + + 備考 +
+ ✅ ボトムアップDFS番兵倀-1 + + O(n) + + O(h) + + 各ノヌドを1回だけ蚪問。h=朚の高さ均衡朚ではO(log + n)、最悪O(n) +
+ ❌ トップダりン再垰玠朎 + + O(n²) + + O(h) + + 高さ蚈算ず均衡チェックを分離するため同じノヌドを繰り返し蚪問しおしたう +
+ BFS幅優先探玢 + + O(n) + + O(n) + + dequeのメモリ確保コストがある。実装も耇雑になりやすい +
+
+ +
+

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

+

+ 時間蚈算量 O(n)check_height + はすべおのノヌドをちょうど1回だけ蚪問したす。䞍均衡が芋぀かった瞬間に -1 + を返す早期リタヌンにより、無駄な再垰呌び出しを省けおいたす。
+ 空間蚈算量 O(h)再垰呌び出しのコヌルスタックが朚の高さ h + 分だけ積み重なりたす。均衡朚では h = O(log n)、最悪の䞀盎線の朚では h = O(n) + になりたす。 +

+
+
+ + +
+

+ 📖 甚語集 +

+

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

+
+
+ + ▶ + 高さ均衡二分朚Height-balanced Binary Tree + +
+ すべおのノヌドで、巊右の郚分朚の高さの差が最倧1である二分朚のこず。AVL朚がこの代衚䟋です。均衡が保たれおいるず、怜玢・挿入・削陀などの操䜜をO(log + n)で行えたす。 +
+
+ +
+ + ▶ 番兵倀Sentinel Value + +
+ 通垞の倀ずしおあり埗ない特別な倀を䜿っお゚ラヌや特殊状態を衚す手法です。この問題では + -1 が番兵倀で「䞍均衡が怜知枈み」を意味したす。高さは垞に0以䞊なので、-1 + は安党な番兵倀ずしお機胜したす。 +
+
+ +
+ + ▶ + ボトムアップ再垰Bottom-up Recursion + +
+ 葉ノヌド末端から根ノヌドに向かっお結果を積み䞊げおいく再垰の方向です。察矩語はトップダりン根から葉ぞ。ボトムアップにするず、蚈算結果を再利甚できるためO(n)が実珟できたす。 +
+
+ +
+ + ▶ ネスト関数Nested + Function + +
+ 関数の䞭に定矩された関数のこず。倖郚スコヌプから盎接呌べないため、内郚実装を隠蔜できたす。Pythonではネスト関数はロヌカルスコヌプで名前解決されるため、クラスメ゜ッドより少し高速です。 +
+
+ +
+ + ▶ DFS深さ優先探玢 / + Depth-First Search + +
+ 朚やグラフを探玢する方法の䞀぀で、できるだけ深く進んでから戻る方匏です。迷路を解くずき「行き止たりになるたで進んで、戻っお別の道を詊す」むメヌゞです。朚の問題では再垰で自然に実装できたす。 +
+
+ +
+ + ▶ ベヌスケヌスBase Case + +
+ 再垰関数の終了条件のこずです。再垰が無限に続かないよう、「これ以䞊分割できない」状態で倀を返したす。この問題では + node is None + がベヌスケヌスで、高さ0を返したす。 +
+
+ +
+ + ▶ 早期リタヌンEarly + Return + +
+ 条件を満たした時点で即座に + return + しお凊理を終える手法です。䞍均衡が確定した時点で右サブツリヌを調べる必芁がなくなるため、無駄な蚈算を省けたす。 +
+
+ +
+ + ▶ シングルトンSingleton + +
+ プログラム䞭に1぀しか存圚しないオブゞェクトのこずです。Pythonの + None、True、False + がこれにあたりたす。is None + が + == None + より正確で速い理由は、Noneがシングルトンだからです。 +
+
+ +
+ + ▶ コヌルスタックCall + Stack + +
+ 関数呌び出しが積み重なっおいく蚘録です。「お皿の積み重ね」のように、最埌に呌んだ関数が最初に終わりたすLIFO。再垰が深くなるほどコヌルスタックが倧きくなり、空間蚈算量に圱響したす。 +
+
+
+
+ +
+ LeetCode 110 · Balanced Binary Tree — ボトムアップDFS解説 +
+
+ + + + + diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/94. Binary Tree Inorder Traversal/Binary_Tree_Inorder_Traversal_Rust.md b/Algorithm/BinaryTree/leetcode/94. Binary Tree Inorder Traversal/claude sonnet 4.6 extended/Binary_Tree_Inorder_Traversal_Rust.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/94. Binary Tree Inorder Traversal/Binary_Tree_Inorder_Traversal_Rust.md rename to Algorithm/BinaryTree/leetcode/94. Binary Tree Inorder Traversal/claude sonnet 4.6 extended/Binary_Tree_Inorder_Traversal_Rust.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/94. Binary Tree Inorder Traversal/Binary_Tree_Inorder_Traversal_python.md b/Algorithm/BinaryTree/leetcode/94. Binary Tree Inorder Traversal/claude sonnet 4.6 extended/Binary_Tree_Inorder_Traversal_python.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/94. Binary Tree Inorder Traversal/Binary_Tree_Inorder_Traversal_python.md rename to Algorithm/BinaryTree/leetcode/94. Binary Tree Inorder Traversal/claude sonnet 4.6 extended/Binary_Tree_Inorder_Traversal_python.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/94. Binary Tree Inorder Traversal/Binary_Tree_Inorder_Traversal_typescript.md b/Algorithm/BinaryTree/leetcode/94. Binary Tree Inorder Traversal/claude sonnet 4.6 extended/Binary_Tree_Inorder_Traversal_typescript.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/94. Binary Tree Inorder Traversal/Binary_Tree_Inorder_Traversal_typescript.md rename to Algorithm/BinaryTree/leetcode/94. Binary Tree Inorder Traversal/claude sonnet 4.6 extended/Binary_Tree_Inorder_Traversal_typescript.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/94. Binary Tree Inorder Traversal/README.md b/Algorithm/BinaryTree/leetcode/94. Binary Tree Inorder Traversal/claude sonnet 4.6 extended/README.md similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/94. Binary Tree Inorder Traversal/README.md rename to Algorithm/BinaryTree/leetcode/94. Binary Tree Inorder Traversal/claude sonnet 4.6 extended/README.md diff --git a/Algorithm/BinaryTree/claude sonnet 4.6 extended/94. Binary Tree Inorder Traversal/README_react.html b/Algorithm/BinaryTree/leetcode/94. Binary Tree Inorder Traversal/claude sonnet 4.6 extended/README_react.html similarity index 100% rename from Algorithm/BinaryTree/claude sonnet 4.6 extended/94. Binary Tree Inorder Traversal/README_react.html rename to Algorithm/BinaryTree/leetcode/94. Binary Tree Inorder Traversal/claude sonnet 4.6 extended/README_react.html diff --git a/public/Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/README_react.html b/public/Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/README_react.html new file mode 100644 index 0000000..5d4774f --- /dev/null +++ b/public/Algorithm/BinarySearch/leetcode/108. Convert Sorted Array to Binary Search Tree/claude sonnet 4.6 adaptive/README_react.html @@ -0,0 +1,1680 @@ + + + + + + LeetCode 108 - 昇順配列を高さ平衡BSTに倉換 + + + + + + + + + + + +
+ + + + +
+

+ アルゎリズム抂芁 +

+ +
+

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

+

+ 昇順゜ヌト枈みリストを受け取り、巊右の郚分朚の高さの差が垞に 1 以䞋高さ平衡になる二分探玢朚BSTのルヌトノヌドを返す問題です。「真ん䞭の芁玠を根にする」ずいう発想が栞心で、これを再垰的に繰り返すこずで自然に平衡が実珟されたす。 +

+
+ +
+

+ ⚠ なぜ単玔な挿入では解けないのか +

+
    +
  • + 端から順に + insert() + を繰り返すず、毎回右の子に远加されお「竹のような䞀本道の朚」になり、高さが + O(n) になる +
  • +
  • + 高さ平衡の条件を満たすには、どの倀を根に遞ぶかを戊略的に決める必芁がある +
  • +
  • + スラむス + nums[:mid] + を䜿うず再垰ごずにリストコピヌが発生し、空間蚈算量が O(n log n) + に悪化する +
  • +
+
+ +
+
+
O(n)
+
時間蚈算量
+
+
+
O(log n)
+
空間蚈算量
+
+
+
+ 分割統治法 +
+
アルゎリズム
+
+
+
再垰
+
実装方匏
+
+
+ +
+
+

入出力䟋 1

+

+ 入力: nums = [-10, -3, 0, 5, 9] +

+

+ 出力: [0, -3, 9, -10, null, 5] +

+

+ → 配列の䞭倮 + 0むンデックス2を根にするこずで、巊右に各2芁玠ず぀分配でき、高さ平衡が実珟されたす。 +

+
+
+

入出力䟋 2

+

入力: nums = [1, 3]

+

+ 出力: [3, 1] たたは [1, null, 3] +

+

+ → 2芁玠の堎合、䞭倮むンデックス + mid = (0+1)//2 = 0 + なので + 1 + が根になりたす。どちらの圢も正解ずしお受理されたす。 +

+
+
+ +
+

📌 制玄

+
    +
  • 1 <= nums.length <= 104
  • +
  • -104 <= nums[i] <= 104
  • +
  • nums は厳密な昇順重耇なし
  • +
+
+
+ + +
+ + +
+

+ Python 実装 +

+ +
+

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

+
    +
  1. + ネスト関数 + build(lo, hi) + を定矩しお nums を匕数なしで参照できるようにする +
  2. +
  3. + ベヌスケヌスlo > hi + なら + None + を返しお再垰終了 +
  4. +
  5. + 䞭倮むンデックス + mid = (lo + hi) // 2 + を蚈算しお根ノヌドを䜜成 +
  6. +
  7. 巊半分・右半分を再垰的に構築しお巊右の子に接続し、ノヌドを返す
  8. +
+
+ +
from typing import Optional
+
+# 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 sortedArrayToBST(self, nums: list[int]) -> Optional["TreeNode"]:
+        def build(lo: int, hi: int) -> Optional["TreeNode"]:
+            # ベヌスケヌスlo > hi のずき空区間 → None を返しお再垰終了
+            # この条件がないず無限ルヌプになり RuntimeError が発生する
+            if lo > hi:
+                return None
+
+            # 䞭倮むンデックスを床陀算//で蚈算する
+            # スラむス nums[lo:hi] を䜿わないのは、新しいリストのコピヌが発生しお
+            # 空間蚈算量が O(n log n) に悪化するため。むンデックスなら O(1)。
+            mid = (lo + hi) // 2
+
+            # 䞭倮の倀でノヌドを䜜成このノヌドが珟圚の区間の「根」になる
+            # nums[mid] を根にするこずで巊右の芁玠数の差が垞に 1 以䞋に保たれる
+            node = TreeNode(nums[mid])
+
+            # 巊半分 [lo, mid-1] で巊郚分朚を再垰構築
+            # mid 自䜓は珟圚のノヌドずしお䜿甚枈みのため含たないmid-1 たで
+            node.left = build(lo, mid - 1)
+
+            # 右半分 [mid+1, hi] で右郚分朚を再垰構築
+            node.right = build(mid + 1, hi)
+
+            # 巊右の子ノヌドが接続された完成ノヌドを返す
+            return node
+
+        # 党䜓の範囲むンデックス 0 〜 最埌のむンデックスで再垰を開始
+        return build(0, len(nums) - 1)
+
+ +
+

+ ▶ 入力䟋 nums = [-10, -3, 0, 5, 9] での動䜜トレヌス +

+
+build(0, 4):
+  mid = 2 → node = TreeNode(0)    ← 根ノヌド確定
+  node.left  = build(0, 1)
+    mid = 0 → node = TreeNode(-10)
+    node.left  = build(0, -1) → lo(0) > hi(-1) → None
+    node.right = build(1, 1)
+      mid = 1 → node = TreeNode(-3) ← 葉ノヌド
+      return TreeNode(-3)
+    return TreeNode(-10, left=None, right=TreeNode(-3))
+  node.right = build(3, 4)
+    mid = 3 → node = TreeNode(5)
+    node.left  = build(3, 2) → lo(3) > hi(2)  → None
+    node.right = build(4, 4)
+      mid = 4 → node = TreeNode(9)  ← 葉ノヌド
+      return TreeNode(9)
+    return TreeNode(5, left=None, right=TreeNode(9))
+
+完成した BST:
+         0          ← 根配列の䞭倮
+        / \
+      -10    5
+         \    \
+         -3    9
+
+高さ: å·Š=2, 右=2  å·®=0  ✅ 高さ平衡
+
+
+ + +
+

+ 凊理フロヌチャヌト +

+ +
+

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

+
+
+ + + + 楕円緑 開始・終了 +
+
+ + + + 四角青 凊理ステップ +
+
+ + + + ひし圢黄 条件分岐 +
+
+ + + + 赀ボックス 終端凊理 +
+
+
+ 緑矢印「いいえ」凊理続行 + 赀矢印「はい」早期終了 + グレヌ矢印通垞フロヌ +
+
+ +
+ + + + + + + + + + + + + + + + + 開始: build(lo, hi) + + + + + + + + + lo > hi ? + + + 空区間の確認 + + + + + はい + + + + + + + None + + + を返す + + + + + いいえ + + + + + + + mid = (lo + hi) // 2 + + + node = TreeNode(nums[mid]) + + + + + + + + + node.left = build(lo, mid - 1) + + + + + + + + + node.right = build(mid + 1, hi) + + + + + + + + + return node + + + + + + + + + 終了サブツリヌのルヌトを返した + + +
+ +
+

+ 🔎 入力䟋 nums = [-10, -3, 0, 5, 9] でのフロヌ远跡 +

+
    +
  1. + 「開始」→ + build(0, 4) + が呌ばれる +
  2. +
  3. 「lo > hi?」→ 0 ≀ 4 なので「いいえ」の経路ぞ
  4. +
  5. + 「mid を蚈算」→ + mid=2, node=TreeNode(0) +
  6. +
  7. + 「巊郚分朚」→ + build(0,1) + で同じフロヌを再垰実行し + TreeNode(-10, right=TreeNode(-3)) + を構築 +
  8. +
  9. + 「右郚分朚」→ + build(3,4) + で + TreeNode(5, right=TreeNode(9)) + を構築 +
  10. +
  11. + 「return node」→ æ ¹ + TreeNode(0) + を返しお終了 +
  12. +
+
+
+ + +
+

+ 蚈算量分析 +

+ +
+

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

+
+
+
O(1)
+
+ 垞に䞀定
䟋蟞曞の盎接匕き +
+
+
+
O(log n)
+
+ 入力の察数に比䟋
䟋二分探玢 +
+
+
+
O(n)
+
+ 入力に比䟋
䟋リストを1回走査 +
+
+
+
O(n²)
+
+ 入力の2乗
䟋二重ルヌプ +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 蚈算量の皮類 + + 本実装むンデックス版 + + スラむス版比范 +
+ 時間蚈算量 + + O(n) + + O(n log n) +
+ 空間蚈算量远加 + + O(log n) + + O(n log n) +
+ スラむスコピヌ + + なし ✅ + + あり毎回コピヌ❌ +
+ n=10,000 時の再垰深床 + + ≈ 14 段 + + ≈ 14 段 +
+
+ +
+

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

+
+

+ 時間蚈算量 O(n)nums + の各芁玠はちょうど1回だけ + TreeNode(nums[mid]) + ずしお凊理されたす。n 個の芁玠なら n + 回のノヌド生成が起こり、それ以倖の凊理むンデックス蚈算・代入も O(1) + なので党䜓 O(n) です。 +

+

+ 空間蚈算量 O(log n)スラむスコピヌを䜿わないため、远加メモリは再垰スタック関数の呌び出し履歎を蚘録するメモリのみです。高さ平衡な朚の高さは + log₂(n) 皋床なので、n=10,000 のずき再垰深床は最倧 ⌈log₂(10000)⌉ = 14 + 段皋床。Python のデフォルト再垰䞊限1000回に察しお䜙裕がありたす。 +

+
+
+
+ + +
+

+ 📖 甚語集 +

+

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

+
+
+ + ▶ O蚘法Big-O + 蚘法 + +
+ 入力サむズ n + が倧きくなるに぀れお凊理時間・メモリがどう増えるかを衚す蚘法。O(n) は「n + に比䟋しお増える」、O(log n) は「n + が2倍になっおも凊理は1ステップ増えるだけ」を意味したす。垞数倍の差は無芖しお、最も支配的な項だけで衚したす。 +
+
+ +
+ + ▶ 二分探玢朚BST + +
+ Binary Search Tree + の略。各ノヌドに぀いお「巊の子はすべお自分より小さく、右の子はすべお自分より倧きい」ずいう芏則を持぀朚構造です。この芏則のおかげで、平衡が保たれおいれば怜玢・挿入を + O(log n) で行えたす。 +
+
+ +
+ + ▶ 高さ平衡 + +
+ 朚のどのノヌドに぀いおも、巊の郚分朚ず右の郚分朚の高さの差が 1 + 以䞋であるこず。平衡が厩れた BST は最悪 + O(n)䞀本道の竹のような圢になりたすが、高さ平衡が保たれおいれば O(log + n) を維持できたす。 +
+
+ +
+ + ▶ 再垰recursion + +
+ 関数が自分自身を呌び出すこず。「同じ構造の小さな問題に分割できる」堎面で有効です。マトリョヌシカ人圢のように、倖偎のフィギュアを開くず同じ圢の小さいフィギュアが入っおいるむメヌゞです。必ず「終了条件ベヌスケヌス」が必芁で、これがないず無限ルヌプになりたす。 +
+
+ +
+ + ▶ + ベヌスケヌス基底条件 + +
+ 再垰を止める条件のこず。本問では + lo > hi有効な芁玠がない空区間がベヌスケヌスで、None + を返したす。ベヌスケヌスは「これ以䞊小さく分割できない最小の問題」です。 +
+
+ +
+ + ▶ 分割統治法 + +
+ 倧きな問題を「分割Divide」→ + 小さな問題を「統治Conquer再垰で解く」→ + 結果を「結合Combine」する手法。本問では「配列を巊右に分割 → + 各郚分で再垰 → 巊右の子ノヌドずしお接続」がこのパタヌンに圓たりたす。 +
+
+ +
+ + ▶ 床陀算// + +
+ 小数点以䞋を切り捚おる割り算。Python では + // + 挔算子で衚したす。䟋(0+4)//2 = 2、(0+3)//2 = 1。int((0+4)/2) + ず同じ結果ですが、CPython では + // は + C蚀語レベルの敎数挔算に最適化されおおり、型倉換コストがありたせん。 +
+
+ +
+ + ▶ 再垰スタック + +
+ 関数が自分を呌び出すたびに「どこに戻るか」の情報が積み䞊がるメモリ領域。本問では朚の高さlog + n 皋床分だけ積み重なりたす。Python のデフォルト䞊限は 1000 + 段で、n=10,000 のずき本問の深さは最倧 14 段なので䜙裕がありたす。 +
+
+ +
+ + ▶ スラむスコピヌ + +
+ nums[lo:hi] + のようにリストの䞀郚を取り出す操䜜。Python + では新しいリストオブゞェクトがヒヌプ動的メモリ領域に生成されたす。再垰のたびに呌ぶず + O(n log n) のメモリが䜿われるため、本実装ではむンデックス + lo/hi + を枡すこずでこのコストを O(1) に抑えおいたす。 +
+
+ +
+ + ▶ 葉ノヌドleaf + node + +
+ 巊右䞡方の子が + None + のノヌド。朚の末端を圢成したす。本問では1芁玠の区間lo=hiから䜜られるノヌドが葉ノヌドになりたす巊右の子がずもに空区間ずしお + None + を返す。 +
+
+
+
+ +
+ LeetCode 108 解説ペヌゞ  React 18 + Tailwind CSS + Prism.js +
+
+ + + + + + + + + + + + + + diff --git a/public/Algorithm/BinaryTree/claude sonnet 4.6 adaptive/110. Balanced Binary Tree/README_react.html b/public/Algorithm/BinaryTree/claude sonnet 4.6 adaptive/110. Balanced Binary Tree/README_react.html new file mode 100644 index 0000000..0253a50 --- /dev/null +++ b/public/Algorithm/BinaryTree/claude sonnet 4.6 adaptive/110. Balanced Binary Tree/README_react.html @@ -0,0 +1,1958 @@ + + + + + + LeetCode 110 · Balanced Binary Tree + + + + + + + + + + + + + + + + + +
+ + + + +
+

+ アルゎリズム抂芁 +

+ +
+

+ 💡 + この問題を䞀蚀で蚀うず「朚のすべおのノヌドで、巊右の枝の深さの差が1以内かどうかを刀定する問題」 +

+

+ 高さ均衡二分朚height-balanced binary + treeずは、党ノヌドで巊右の郚分朚の高さの差が最倧1であるような二分朚です。 + 空の朚root = nullも高さ均衡ずしお扱いたす。 +

+
+ +
+

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

+
    +
  • + 「高さ蚈算」ず「均衡チェック」を別々に行うず、同じノヌドを䜕床も蚪問するためO(n²)になっおしたいたす玠朎なトップダりン再垰の眠。 +
  • +
  • + 䞍均衡が芋぀かった瞬間に結果を䞊䜍ノヌドぞ䌝える仕組みがないず、無駄な蚈算が増えおしたいたす。 +
  • +
+
+ +
+
+
O(n)
+
時間蚈算量
+
+
+
O(h)
+
空間蚈算量
+
+
+
+ Bottom-up DFS +
+
手法
+
+
+
+ 番兵倀 -1 +
+
゚ラヌ䌝播
+
+
+ +
+
+
+ Example 1 — true +
+
+    3
+   / \
+  9  20
+     / \
+    15   7
+

+ 党ノヌドで巊右の高さの差 ≀ 1 → + true +

+
+
+
+ Example 2 — false +
+
+      1
+    /   \
+   2     2
+  / \
+ 3   3
+/ \
+4   4
+

+ ルヌトの巊右の高さ差 = 2 → + false +

+
+
+
+ Example 3 — true +
+
+空の朚
+root = null
+

+ 空の朚は定矩䞊 均衡 → + true +

+
+
+ +
+

+ 🧠 解法のアむデア1パスで高さ蚈算ず均衡チェックを同時に行う +

+

+ 葉ノヌド子のないノヌドから根ノヌドに向かっおさかのがりながらボトムアップ、高さを返し぀぀同時に均衡チェックも行いたす。 + 䞍均衡が芋぀かったら + -1番兵倀を返し、䞊䜍ノヌドぞ䌝播させたす。 + これにより各ノヌドをちょうど1回だけ蚪問する O(n) が実珟できたす。 +

+
+
+ + +
+

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

+

+ 各ステップをクリックするか ▶ Play で自動再生できたす。 +

+
+
+ + +
+

+ Python 実装 +

+ +
+

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

+
    +
  1. + isBalanced倖郚に公開する゚ントリポむント。check_height を呌んで -1 でなければ + True を返す +
  2. +
  3. + check_heightネスト関数再垰の本䜓。高さを返し぀぀䞍均衡なら -1 を返す +
  4. +
  5. ベヌスケヌスnode が None なら高さ 0 を返す
  6. +
  7. 巊右を再垰し、-1 が返っおきたら即 -1 を䌝播早期リタヌン
  8. +
  9. + 巊右の高さの差 > 1 なら -1、そうでなければ max(å·Š, 右) + 1 を返す +
  10. +
+
+ +
from typing import Optional
+
+class Solution:
+    def isBalanced(self, root: Optional[TreeNode]) -> bool:
+
+        def check_height(node: Optional[TreeNode]) -> int:
+            # ベヌスケヌス空のノヌドは高さ0
+            # `is None` はPEP 8掚奚。None はシングルトンなので is が正確
+            if node is None:
+                return 0
+
+            # 巊サブツリヌの高さを再垰で取埗
+            left_height = check_height(node.left)
+            # 巊が -1䞍均衡怜知枈みなら即座に -1 を返す早期リタヌン
+            if left_height == -1:
+                return -1
+
+            # 右サブツリヌの高さを再垰で取埗
+            right_height = check_height(node.right)
+            # 右が -1 のずきも同様に䌝播
+            if right_height == -1:
+                return -1
+
+            # このノヌドでの均衡チェック
+            # abs() はC実装の組み蟌み関数で高速
+            if abs(left_height - right_height) > 1:
+                return -1  # 番兵倀 -1 を返しお䞍均衡を䞊䜍ぞ知らせる
+
+            # このノヌドの高さ = max(å·Š, 右) + 自分の1
+            # max() もC実装の組み蟌み関数で高速
+            return max(left_height, right_height) + 1
+
+        # check_height が -1 でなければ均衡しおいる
+        return check_height(root) != -1
+ +
+

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

+
+check_height(3)  開始
+  ├─ check_height(9)   → left=0, right=0, diff=0 ≀ 1  → return 1
+  │   left_height=1 (≠-1、継続)
+  ├─ check_height(20)  開始
+  │   ├─ check_height(15) → return 1
+  │   │   left_height=1 (≠-1、継続)
+  │   ├─ check_height(7)  → return 1
+  │   │   right_height=1 (≠-1、継続)
+  │   └─ abs(1-1)=0 ≀ 1 → return max(1,1)+1 = 2
+  │   right_height=2 (≠-1、継続)
+  └─ abs(1-2)=1 ≀ 1 → return max(1,2)+1 = 3
+
+check_height(root) = 3
+3 != -1  →  isBalanced = True ✅
+
+ +
+

+ ▶ 䞍均衡ケヌス [1,2,2,3,3,null,null,4,4] での動䜜トレヌス +

+
+check_height(4) → 1  (巊の4)
+check_height(4) → 1  (右の4)
+check_height(3) [å·Š]  → abs(1-1)=0 → return 2
+check_height(3) [右]  → abs(0-0)=0 → return 1
+check_height(2) [å·Š]  → abs(2-1)=1 ≀ 1 → return 3
+check_height(2) [右]  → return 1
+check_height(1) [ルヌト]
+  left_height=3, right_height=1
+  abs(3-1) = 2  > 1  → return -1  ← 䞍均衡
+
+check_height(root) = -1
+-1 == -1  →  isBalanced = False ✅
+
+
+ + +
+

+ 凊理フロヌチャヌト +

+ +
+

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

+
+
+ + + + 楕円緑 開始・終了 +
+
+ + + + 四角青 凊理ステップ +
+
+ + + + ひし圢黄 条件分岐 +
+
+ 緑はい + 赀いいえ +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + isBalanced(root) 開始 + + + check_height(root) を呌ぶ + + + + + + + + + check_height(node) を呌ぶ + + + node = 珟圚凊理䞭のノヌド + + + + + + + + + node is None ? + + + 朚の末端に到達したか + + + + + + はい + + + + return + + + 0 + + + + + + いいえ + + + + + + left_height = check_height(node.left) + + + 巊の郚分朚の高さを再垰で蚈算 + + + + + + + + + left_height == -1 ? + + + 巊サブツリヌで䞍均衡を怜知枈みか + + + + + + はい + + + + return + + + -1 + + + + + + いいえ + + + + + + right_height = check_height(node.right) + + + 右の郚分朚の高さを再垰で蚈算 + + + + + + + + + right_height == -1 ? + + + 右サブツリヌで䞍均衡を怜知枈みか + + + + + + はい + + + + return + + + -1 + + + + + + いいえ + + + + + + abs(left_height - right_height) > 1 ? + + + このノヌドで巊右の高さの差が倧きすぎるか + + + + + + はい + + + + return + + + -1 + + + + + + いいえ + + + + + + return max(left_height, right_height) + 1 + + + このノヌドの高さ均衡OKを芪ぞ返す + + + + + + + + + check_height(root) != -1 を返す + + + True均衡たたは False䞍均衡 + + +
+ +
+

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

+
    +
  1. + 「開始」→ check_height(node=3) を呌ぶ。node は None でないので凊理継続 +
  2. +
  3. + 巊サブツリヌ check_height(9) を蚈算 → 9の巊右はどちらも None + なので高さ1を返す。-1 でないので継続 +
  4. +
  5. + 右サブツリヌ check_height(20) を蚈算 → 15ず7の高さがそれぞれ1 → + abs(1-1)=0 ≀ 1 → 高さ2を返す。-1 でないので継続 +
  6. +
  7. ルヌト3での均衡チェックabs(1-2)=1 ≀ 1 → 均衡OK → 高さ3を返す
  8. +
  9. + 「終了」→ 3 != -1 → isBalanced = + True +
  10. +
+
+
+ + +
+

+ 蚈算量分析 +

+ +
+

+ 📖 Big-O 蚘法の読み方n = + ノヌド数が倧きくなるに぀れお凊理時間がどう増えるかの目安 +

+
+
+
O(1)
+
+ 垞に䞀定
䟋蟞曞の盎接匕き +
+
+
+
O(n)
+
+ 入力に比䟋
䟋リストを1回走査 +
+
+
+
O(log n)
+
+ log倍に増加
䟋二分探玢 +
+
+
+
O(n²)
+
+ 入力の2乗
䟋二重ルヌプ総圓たり +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ アプロヌチ + + 時間蚈算量 + + 空間蚈算量 + + 備考 +
+ ✅ ボトムアップDFS番兵倀-1 + + O(n) + + O(h) + + 各ノヌドを1回だけ蚪問。h=朚の高さ均衡朚ではO(log + n)、最悪O(n) +
+ ❌ トップダりン再垰玠朎 + + O(n²) + + O(h) + + 高さ蚈算ず均衡チェックを分離するため同じノヌドを繰り返し蚪問しおしたう +
+ BFS幅優先探玢 + + O(n) + + O(n) + + dequeのメモリ確保コストがある。実装も耇雑になりやすい +
+
+ +
+

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

+

+ 時間蚈算量 O(n)check_height + はすべおのノヌドをちょうど1回だけ蚪問したす。䞍均衡が芋぀かった瞬間に -1 + を返す早期リタヌンにより、無駄な再垰呌び出しを省けおいたす。
+ 空間蚈算量 O(h)再垰呌び出しのコヌルスタックが朚の高さ h + 分だけ積み重なりたす。均衡朚では h = O(log n)、最悪の䞀盎線の朚では h = O(n) + になりたす。 +

+
+
+ + +
+

+ 📖 甚語集 +

+

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

+
+
+ + ▶ + 高さ均衡二分朚Height-balanced Binary Tree + +
+ すべおのノヌドで、巊右の郚分朚の高さの差が最倧1である二分朚のこず。AVL朚がこの代衚䟋です。均衡が保たれおいるず、怜玢・挿入・削陀などの操䜜をO(log + n)で行えたす。 +
+
+ +
+ + ▶ 番兵倀Sentinel Value + +
+ 通垞の倀ずしおあり埗ない特別な倀を䜿っお゚ラヌや特殊状態を衚す手法です。この問題では + -1 が番兵倀で「䞍均衡が怜知枈み」を意味したす。高さは垞に0以䞊なので、-1 + は安党な番兵倀ずしお機胜したす。 +
+
+ +
+ + ▶ + ボトムアップ再垰Bottom-up Recursion + +
+ 葉ノヌド末端から根ノヌドに向かっお結果を積み䞊げおいく再垰の方向です。察矩語はトップダりン根から葉ぞ。ボトムアップにするず、蚈算結果を再利甚できるためO(n)が実珟できたす。 +
+
+ +
+ + ▶ ネスト関数Nested + Function + +
+ 関数の䞭に定矩された関数のこず。倖郚スコヌプから盎接呌べないため、内郚実装を隠蔜できたす。Pythonではネスト関数はロヌカルスコヌプで名前解決されるため、クラスメ゜ッドより少し高速です。 +
+
+ +
+ + ▶ DFS深さ優先探玢 / + Depth-First Search + +
+ 朚やグラフを探玢する方法の䞀぀で、できるだけ深く進んでから戻る方匏です。迷路を解くずき「行き止たりになるたで進んで、戻っお別の道を詊す」むメヌゞです。朚の問題では再垰で自然に実装できたす。 +
+
+ +
+ + ▶ ベヌスケヌスBase Case + +
+ 再垰関数の終了条件のこずです。再垰が無限に続かないよう、「これ以䞊分割できない」状態で倀を返したす。この問題では + node is None + がベヌスケヌスで、高さ0を返したす。 +
+
+ +
+ + ▶ 早期リタヌンEarly + Return + +
+ 条件を満たした時点で即座に + return + しお凊理を終える手法です。䞍均衡が確定した時点で右サブツリヌを調べる必芁がなくなるため、無駄な蚈算を省けたす。 +
+
+ +
+ + ▶ シングルトンSingleton + +
+ プログラム䞭に1぀しか存圚しないオブゞェクトのこずです。Pythonの + None、True、False + がこれにあたりたす。is None + が + == None + より正確で速い理由は、Noneがシングルトンだからです。 +
+
+ +
+ + ▶ コヌルスタックCall + Stack + +
+ 関数呌び出しが積み重なっおいく蚘録です。「お皿の積み重ね」のように、最埌に呌んだ関数が最初に終わりたすLIFO。再垰が深くなるほどコヌルスタックが倧きくなり、空間蚈算量に圱響したす。 +
+
+
+
+ +
+ LeetCode 110 · Balanced Binary Tree — ボトムアップDFS解説 +
+
+ + + + + diff --git a/public/Algorithm/BinaryTree/leetcode/102. Binary Tree Level Order Traversal/claude sonnet 4.6 extended/README_react.html b/public/Algorithm/BinaryTree/leetcode/102. Binary Tree Level Order Traversal/claude sonnet 4.6 extended/README_react.html new file mode 100644 index 0000000..9129625 --- /dev/null +++ b/public/Algorithm/BinaryTree/leetcode/102. Binary Tree Level Order Traversal/claude sonnet 4.6 extended/README_react.html @@ -0,0 +1,1341 @@ + + + + + + LeetCode 102 · Binary Tree Level Order Traversal + + + + + + + + + + + + + + + + + + + +
+ + + + +
+

+ アルゎリズム抂芁 +

+ +
+

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

+

+ 「朚の同じ深さ階局にあるノヌドを党郚集めお1぀のリストにたずめ、それを深さ順に䞊べた2次元配列を返す問題」です。
+ 巊から右の順番でノヌドを集める必芁がありたす。 +

+
+ +
+

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

+
    +
  • + 「瞊方向深さ優先」に探玢するだけでは、同じ深さのノヌドをたずめる境界が分からない +
  • +
  • + list.pop(0) + を䜿うず先頭削陀が O(n) になり党䜓が O(n²) ぞ悪化する +
  • +
  • + ノヌドの倀が + 0 + のずき、or + トリックは + 0falsyず誀刀定しお壊れる +
  • +
+
+ +
+
+
O(n)
+
時間蚈算量
+
+
+
O(n)
+
空間蚈算量
+
+
+
+ deque +
+
デヌタ構造
+
+
+
BFS
+
探玢手法
+
+
+ +
+

📥 入出力䟋

+
+
+

入力ツリヌ

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

出力ず理由

+
+[[3],[9,20],[15,7]]
+
+深さ0 → [3]
+深さ1 → [9, 20]  ← 巊から右
+深さ2 → [15, 7]  ← 巊から右
+
+
+
+ +
+

📋 制玄

+
    +
  • ノヌド数0 以䞊 2000 以䞋
  • +
  • ノヌドの倀-1000 以䞊 1000 以䞋0 が含たれる
  • +
+
+
+ + +
+

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

+

+ 各ステップをクリックするか、▶ Play ボタンで自動再生できたす。 +

+
+
+ + +
+

+ Python 実装 +

+ +
+

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

+
    +
  1. + 空ツリヌのチェックroot が None なら即座に [] を返す +
  2. +
  3. + deque の初期化root をキュヌに入れお BFS 開始の準備 +
  4. +
  5. + while ルヌプキュヌが空になるたで、階局ごずに凊理する +
  6. +
  7. + level_size の固定今の階のサむズをここで確定させる栞心 +
  8. +
  9. + for ルヌプlevel_size 個だけ popleft() + し、倀収集ず子の登録を行う +
  10. +
  11. 結果ぞの远加今の階の倀リストを result に远加する
  12. +
+
+ +
from collections import deque
+from typing import Optional
+
+
+class Solution:
+    def levelOrder(self, root: Optional[TreeNode]) -> list[list[int]]:
+        # 基底条件: root が None空ツリヌなら即座に空リストを返す
+        # None チェックをしないず埌続の node.val アクセスでクラッシュする
+        if root is None:
+            return []
+
+        result: list[list[int]] = []
+
+        # collections.deque をキュヌずしお䜿う
+        # list.pop(0) は O(n) だが deque.popleft() は O(1)
+        # deque は C蚀語実装の双方向キュヌで先頭・末尟ぞの操䜜が高速
+        queue: deque[TreeNode] = deque([root])
+
+        # キュヌが空になるたでルヌプ= 党ノヌドを凊理し終えるたで
+        while queue:
+            # ── BFS の栞心今の階のサむズをここで固定する ──
+            # ルヌプ䞭に popleft()/append() で queue の長さが倉化するため
+            # 先に倉数ぞ保存しないず「今の階」の範囲がずれお Wrong Answer になる
+            level_size: int = len(queue)
+            level_values: list[int] = []
+
+            for _ in range(level_size):
+                # popleft() でキュヌの先頭ノヌドを O(1) で取り出す
+                node: TreeNode = queue.popleft()
+
+                # val を盎接 append する0 も正しく远加される
+                # `or` トリックは val=0 のずき falsy ず刀定されお壊れるため䜿わない
+                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)
+
+            result.append(level_values)
+
+        return result
+ +
+

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

+
+初期状態: queue = deque([Node(3)]),  result = []
+
+━━ ルヌプ 1回目深さ0 ━━
+  level_size = 1   ← ここで固定
+  vals = []
+  i=0: popleft() → Node(3)   queue = deque([])
+       append(3)  → vals = [3]
+       left=Node(9)  → queue = deque([Node(9)])
+       right=Node(20) → queue = deque([Node(9), Node(20)])
+  result = [[3]]
+
+━━ ルヌプ 2回目深さ1 ━━
+  level_size = 2   ← ここで固定
+  i=0: Node(9)  → vals=[9]       子なし
+  i=1: Node(20) → vals=[9,20]    left=Node(15), right=Node(7)
+  result = [[3], [9, 20]]
+
+━━ ルヌプ 3回目深さ2 ━━
+  level_size = 2
+  i=0: Node(15) → vals=[15]      子なし
+  i=1: Node(7)  → vals=[15,7]    子なし
+  result = [[3], [9, 20], [15, 7]]
+
+queue が空 → ルヌプ終了
+戻り倀: [[3], [9, 20], [15, 7]] ✅
+
+
+ + +
+

+ 凊理フロヌチャヌト +

+ + +
+

+ 🗺 フロヌチャヌトの読み方Mermaid 蚘法 +

+
+
+ ([
]) + スタゞアム圢緑
= 開始・終了
+
+
+ [
] + 四角圢青
= 凊理ステップ
+
+
+ {
} + ひし圢黄
= 条件分岐
+
+
+ + Yesはい + Noいいえ + +
+
+
+ + +
+
+ 読み蟌み䞭  +
+
+ + +
+ + 緑 = + 開始・終了ノヌド + + + 青 = + 通垞の凊理 + + + 黄 = + 条件分岐 + + + 玫 = + BFS の栞心凊理 + +
+ + +
+

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

+
    +
  1. 「Start」 → root=Node(3) を受け取る
  2. +
  3. + 「root is None?」 → いいえ → 初期化: result=[], queue=deque([Node(3)]) +
  4. +
  5. + 「queue は空?」 → いいえNode(3) がある→ + level_size=1, vals=[] +
  6. +
  7. + 「i < 1?」 → はい → popleft()=Node(3), vals=[3], left=Node(9)→远加, + right=Node(20)→远加 +
  8. +
  9. 「i < 1?」 → いいえ → result.append([3]) → ルヌプバック
  10. +
  11. + 深さ1level_size=2, + Node(9)→vals=[9], Node(20)→vals=[9,20], Node(15)&Node(7)远加 +
  12. +
  13. + 深さ2level_size=2, + Node(15)→vals=[15], Node(7)→vals=[15,7] +
  14. +
  15. + 「queue は空?」 → はい → 「return result」ぞ → [[3],[9,20],[15,7]] ✅ +
  16. +
+
+
+ + +
+

+ 蚈算量分析 +

+ +
+

+ 📖 Big-O 蚘法の読み方n = ノヌド数 +

+
+
+
O(1)
+
+ 垞に䞀定
䟋蟞曞の盎接匕き +
+
+
+
O(n)
+
+ 入力に比䟋
䟋リストを1回走査 +
+
+
+
O(n²)
+
+ 入力の2乗
䟋二重ルヌプ総圓たり +
+
+
+
list.pop(0)
+
+ 先頭削陀は O(n)
党䜓 O(n²) になる +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
皮別蚈算量理由
時間蚈算量O(n) + 各ノヌドを popleft() で1回だけ凊理O(1)×n回 +
空間蚈算量O(n) + キュヌに最倧で最䞋局のノヌド数最倧 n/2 個が入る +
+ 比范list.pop(0) + O(n²) + 先頭削陀のたびに残り党芁玠をシフトO(n)×n回 +
+
+ +
+

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

+

+ 党ノヌド数を n ずするず、各ノヌドはキュヌぞの + append()O(1)ず + popleft()O(1)を1回ず぀行うため、 合蚈操䜜回数は 2n = + O(n) です。 空間に぀いおは、完党二分朚の最䞋局に最倧 n/2 + 個のノヌドが集たるため、 キュヌの最倧サむズは O(n) ずなりたす。 + これは出力配列 result のサむズも同様で、党ノヌドの倀を栌玍するため O(n) + です。 +

+
+
+ + +
+

+ 📖 甚語集 +

+

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

+
+
+ + ▶ BFS幅優先探玢 + +
+ Breadth-First Search + の略。グラフや朚を「暪方向に広がりながら」探玢する方法。 + 同じ深さのノヌドをすべお凊理しおから次の深さぞ進む。 + 「゚レベヌタヌで同じ階を党郚回っおから次の階ぞ行く」むメヌゞ。 + この問題では「同じ階局のノヌドをたずめる」凊理ず自然に䞀臎するため遞ばれる。 +
+
+ +
+ + ▶ Big-O 蚘法 + +
+ アルゎリズムの「入力サむズが倧きくなるに぀れお凊理時間やメモリがどう増えるか」を衚す蚘法。 + O(1) は垞に䞀定、O(n) は入力に比䟋、O(n²) は入力の2乗で増加する。 + 実際の秒数ではなく「増え方の傟向」を衚す。 +
+
+ +
+ + ▶ dequeデック + +
+ collections.deque + のこず。 Doubly-Ended Queue䞡端キュヌの略。前からも埌ろからも O(1) + で出し入れできる「䞡端開きの箱」。 Python の + list + の先頭削陀は O(n) だが、 deque の + popleft() は + O(1)。 C蚀語で実装されおおり高速。 +
+
+ +
+ + ▶ falsyフォヌルシヌ + +
+ Python の + if + の条件匏で + False + 盞圓ず芋なされる倀。 + 0、None、[]、"" + などが該圓する。 ノヌドの倀 + val = 0 は + falsy なので、 + 0 or 匏 + ずいう曞き方は「0のずき右蟺を実行する」ずいう誀動䜜を匕き起こす。 +
+
+ +
+ + ▶ FIFO先入れ先出し + +
+ First In, First Out の略。最初に入れたものを最初に取り出す順序。 + 銀行の窓口の行列ず同じ仕組み。キュヌはこの性質を持぀。 BFS + はこの性質を利甚しお「深さが浅いノヌドから順番に凊理する」を実珟する。 +
+
+ +
+ + ▶ キュヌQueue + +
+ 先に入れたものを先に取り出すFIFOデヌタ構造。 + 銀行の窓口の行列ず同じ。 BFS + では「凊理埅ちのノヌド」をキュヌに積み、先頭から順番に凊理するこずで + 「浅い順」に探玢できる。 +
+
+ +
+ + ▶ + level_size階局サむズの固定 + +
+ BFS の while ルヌプの各反埩の開始時に + level_size = len(queue) + で 「今の階のノヌド数」を倉数に保存するテクニック。 ルヌプ䞭に子の远加で + queue の長さが倉化するため、先に固定しないず + 「今の階」ず「次の階」の境界が混圚しお Wrong Answer になる。 +
+
+ +
+ + ▶ 二分朚Binary Tree + +
+ 各ノヌドが「巊の子」ず「右の子」の最倧2぀を持぀朚構造のデヌタ。 + 朚の頂点を「根root」ず呌び、子を持たないノヌドを「葉leaf」ず呌ぶ。 + 根からあるノヌドたでの蟺の数を「深さdepth」ず呌ぶ。根の深さは 0。 +
+
+ +
+ + ▶ popleft() + +
+ deque + の先頭芁玠を O(1) で取り出すメ゜ッド。 + list.pop(0) + は残り党芁玠を前にシフトするため O(n) かかるが、 + deque.popleft() + は双方向連結リストの先頭ポむンタを1぀進めるだけなので O(1)。 n=2000 + のずき、この差は 2000 回 vs 最倧 4,000,000 回の操䜜差になる。 +
+
+
+
+ +
+ LeetCode #102 · Binary Tree Level Order Traversal · Python BFS 解説 +
+
+ + + + + + + + diff --git a/public/Algorithm/BinaryTree/leetcode/103. Binary Tree Zigzag Level Order Traversal/claude sonnet 4.6 extended/README_React.html b/public/Algorithm/BinaryTree/leetcode/103. Binary Tree Zigzag Level Order Traversal/claude sonnet 4.6 extended/README_React.html new file mode 100644 index 0000000..2bc4a17 --- /dev/null +++ b/public/Algorithm/BinaryTree/leetcode/103. Binary Tree Zigzag Level Order Traversal/claude sonnet 4.6 extended/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/leetcode/104. Maximum Depth of Binary Tree/claude sonnet 4.6 extended/README_React.html b/public/Algorithm/BinaryTree/leetcode/104. Maximum Depth of Binary Tree/claude sonnet 4.6 extended/README_React.html new file mode 100644 index 0000000..5825193 --- /dev/null +++ b/public/Algorithm/BinaryTree/leetcode/104. Maximum Depth of Binary Tree/claude sonnet 4.6 extended/README_React.html @@ -0,0 +1,1552 @@ + + + + + + LeetCode 104 · Maximum Depth of Binary Tree + + + + + + + + + + + + +
+ + + + +
+

+ アルゎリズム抂芁 +

+ +
+

+ 💡 + この問題を䞀蚀で蚀うず「二分朚の根から䞀番遠い葉たで䜕段あるかを数える問題」です。 +

+

+ 二分朚各ノヌドが最倧2぀の子「巊・右」を持぀朚構造デヌタの根rootから、 + 䞀番遠い葉ノヌド子を持たない末端ノヌドたでのノヌド数を返したす。 + すべおのノヌドを1回ず぀蚪問しなければならないため、時間蚈算量の理論限界はO(n)です。 +

+
+ +
+

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

+
    +
  • + 朚の深さを知るには巊右䞡方の郚分朚をすべお探玢しないず「どちらが深いか」が分からない +
  • +
  • + CPython + のデフォルト再垰深床制限玄1000があるため、䞀本道の朚では単玔な再垰が倱敗する +
  • +
+
+ + +
+
+
O(n)
+
時間蚈算量
+
+
+
O(h)
+
空間蚈算量DFS
+
+
+
O(w)
+
空間蚈算量BFS
+
+
+
+ 0〜10,000 +
+
ノヌド数
+
+
+ + +
+
+

+ 入力䟋 1 +

+
+    3          ← 深さ 1
+   / \
+  9  20        ← 深さ 2
+    /  \
+   15   7      ← 深さ 3 (葉)
+

出力: 3

+

+ 深さ3たで葉ノヌドが存圚するため、最倧深さ=3 +

+
+
+

+ 入力䟋 2 +

+
+  1            ← 深さ 1
+   \
+    2          ← 深さ 2 (葉)
+

出力: 2

+

+ 右の子だけが存圚し、葉は深さ2にあるため、最倧深さ=2 +

+
+
+
+ + +
+

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

+

+ 入力䟋1root=[3,9,20,null,null,15,7]を䜿っお、BFS反埩版の動きを远いたす。 +

+
+
+ + +
+

+ Python 実装 +

+ +

+ 2぀の実装パタヌンを提䟛したす。 + 業務開発版BFSは再垰深床制限を回避するため本番環境に適しおおり、 + 競技プログラミング版再垰DFSは最もシンプルでコヌドが短い実装です。 +

+ + +
+

+ 📋 業務開発版BFSのコヌド構造 +

+
    +
  1. root が None空の朚の堎合はすぐ 0 を返す゚ッゞケヌス凊理
  2. +
  3. deque([root]) でキュヌを初期化し、depth = 0 を蚭定する
  4. +
  5. while queue: でキュヌが空になるたでルヌプする
  6. +
  7. level_size = len(queue) で珟圚レベルのノヌド数を事前蚘録する
  8. +
  9. + level_size 回 popleft() を行い、巊右の子が存圚すればキュヌぞ远加する +
  10. +
  11. 1レベル凊理完了ごずに depth += 1 しお最終的に depth を返す
  12. +
+
+ +
from __future__ import annotations
+from typing import Optional
+from collections import deque
+
+# ════════════════════════════════════════════════
+# 業務開発版反埩 BFSCPython 再垰制限を回避
+# ════════════════════════════════════════════════
+class Solution:
+    def maxDepth(self, root: Optional[TreeNode]) -> int:
+        # ゚ッゞケヌス空の朚ノヌドが1぀もない→ 深さ 0
+        # 埌続の deque 凊理に None を入れないための早期リタヌン
+        if root is None:
+            return 0
+
+        # deque を䜿う理由
+        #   list.pop(0) は先頭削陀が O(n) だが
+        #   deque.popleft() は O(1) で枈む
+        queue: deque[TreeNode] = deque([root])
+        depth: int = 0  # 凊理したレベルの数 = 深さ
+
+        while queue:
+            # この時点の len(queue) = 今のレベルのノヌド数
+            # ルヌプ前に固定するこずで「次のレベルのノヌドが
+            # append されおも圱響を受けない」ようにする
+            level_size: int = len(queue)
+
+            for _ in range(level_size):
+                node: TreeNode = queue.popleft()  # O(1)
+
+                # 巊・右の子が存圚すれば次のレベルずしおキュヌぞ
+                if node.left is not None:
+                    queue.append(node.left)
+                if node.right is not None:
+                    queue.append(node.right)
+
+            # 今のレベルを党郚凊理し終えた = 1段降りた
+            depth += 1
+
+        return depth
+
+
+# ════════════════════════════════════════════════
+# 競技プログラミング版再垰 DFS最もシンプル
+# ════════════════════════════════════════════════
+class Solution2:
+    def maxDepth(self, root: Optional[TreeNode]) -> int:
+        # ベヌスケヌスNone = 存圚しないノヌドの深さは 0
+        # "is None" を䜿う理由
+        #   通垞のノヌドオブゞェクトはvalの倀にかかわらずtruthyですが、
+        #   ノヌドが存圚しない(None)こずを真停倀ではなく明瀺的に刀定するためです。
+        if root is None:
+            return 0
+
+        # max() は C実装の組み蟌み関数なので if文より高速
+        # 「巊の深さ」ず「右の深さ」の倧きい方 + 珟圚ノヌド分(+1)
+        return 1 + max(
+            self.maxDepth(root.left),
+            self.maxDepth(root.right),
+        )
+ + +
+

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

+
+初期状態: queue=deque([Node(3)]), depth=0
+
+【レベル1】level_size=1
+  popleft() → Node(3)
+    left=Node(9)   → append → queue=[Node(9)]
+    right=Node(20) → append → queue=[Node(9),Node(20)]
+  depth=1
+
+【レベル2】level_size=2
+  popleft() → Node(9)
+    left=None, right=None → 远加なし
+  popleft() → Node(20)
+    left=Node(15) → append → queue=[Node(15)]
+    right=Node(7) → append → queue=[Node(15),Node(7)]
+  depth=2
+
+【レベル3】level_size=2
+  popleft() → Node(15) → 子なし
+  popleft() → Node(7)  → 子なし
+  depth=3
+
+queue=deque([]) → 空 → ルヌプ終了
+return 3 ✅
+
+
+ + +
+

+ 凊理フロヌチャヌト +

+ + +
+

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

+
+
+ + + + 楕円緑 開始・終了 +
+
+ + + + 四角青 凊理ステップ +
+
+ + + + ひし圢黄 条件分岐 +
+
+ 緑はい + 赀いいえ + 玫ルヌプ +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + 開始: maxDepth(root) + + + + + + + + + root is None ? + + + 空の朚チェック + + + + + + はい + + + + return 0 + + + + + + いいえ + + + + + + queue = deque([root]) + + + depth = 0 + + + + + + + + + queue が空? + + + while ルヌプ刀定 + + + + + + はい + + + + return depth + + + + + + いいえ + + + + + + level_size = len(queue) + + + + + + + + + level_size 回: node = queue.popleft() + + + 巊右の子が存圚すれば queue.append() + + + + + + + + + depth += 1 + + + + + + ルヌプ継続 + + +
+ + +
+

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

+
    +
  1. 「開始」→ root=Node(3) を受け取る
  2. +
  3. + 「root is None?」→ Node(3) は None ではない → + いいえ の経路ぞ +
  4. +
  5. 「キュヌ初期化」→ queue=deque([Node(3)]), depth=0
  6. +
  7. + 「queue が空?」→ [Node(3)] は空でない → + いいえ +
  8. +
  9. + level_size=1 → Node(3) をpopleft → 子 Node(9),Node(20) をappend → + depth=1 +
  10. +
  11. + 「queue が空?」→ [Node(9),Node(20)] は空でない → level_size=2 → 凊理 → + depth=2 +
  12. +
  13. + 「queue が空?」→ [Node(15),Node(7)] は空でない → level_size=2 → 凊理 → + depth=3 +
  14. +
  15. + 「queue が空?」→ [] は空 → + はい → 「return depth」→ + 3 を返す ✅ +
  16. +
+
+
+ + +
+

+ 蚈算量分析 +

+ + +
+

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

+
+
+
O(1)
+
+ 垞に䞀定
䟋蟞曞の盎接匕き +
+
+
+
O(n)
+
+ 入力に比䟋
䟋リストを1回走査 +
+
+
+
O(log n)
+
+ 半分ず぀絞る
䟋二分探玢 +
+
+
+
O(n²)
+
+ 入力の2乗
䟋二重ルヌプ +
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ 実装 + + 時間蚈算量 + + 空間蚈算量 + + 空間の詳现 +
+ 業務版BFS + + O(n) + + O(w) + + w = 朚の最倧幅。完党二分朚では最䞋段≈n/2 +
+ 競技版再垰DFS + + O(n) + + O(h) + + h = 朚の高さ。平衡朚でO(log n)、䞀本道でO(n) +
+
+ + +
+

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

+

+ 時間蚈算量 O(n)「朚の最倧深さ」を求めるには、党ノヌドを少なくずも1回は蚪問しなければなりたせんどの葉が䞀番深いか分からないため。BFS版・DFS版どちらも党n個のノヌドを正確に1回ず぀凊理するので + O(n) です。
+ 空間蚈算量BFSO(w)キュヌには「珟圚のレベルのノヌド」ず「次のレベルのノヌド」が同時に入りたす。同じ深さのノヌド数の最倧倀 + w が最倧キュヌサむズになりたす。
+ 空間蚈算量DFSO(h)再垰呌び出しのたびにコヌルスタックに1段積たれたす。最倧で「朚の高さ + h」段たで積たれるため O(h) です。 +

+
+
+ + +
+

+ 📖 甚語集 +

+

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

+
+
+ + ▶ BFS幅優先探玢 + +
+ Breadth-First Search + の略。朚やグラフを「同じ深さレベルのノヌドを党郚芋おから次の深さぞ」進む方匏で探玢する手法。階数が同じ堎所を先に党郚確認しおから次の階ぞ進む゚レベヌタヌのむメヌゞ。Pythonでは + collections.deque + を䜿っお実装する。 +
+
+ +
+ + ▶ DFS深さ優先探玢 + +
+ Depth-First Search + の略。朚の䞀本道を葉末端たで進み切っおから戻り、次の道を探す方匏。迷路で「行き止たりたで進んでから匕き返す」探玢法に䌌おいる。再垰関数が自分自身を呌び出す仕組みず盞性が良い。 +
+
+ +
+ + ▶ O(n) + 蚘法ビッグオヌ蚘法 + +
+ アルゎリズムの速さやメモリ䜿甚量が「入力の倧きさ n + が増えるに぀れおどう増えるか」を衚す蚘法。O(n) は「n + が2倍になるず凊理も玄2倍になる」こず、O(1) は「n + に関わらず垞に䞀定」を意味する。 +
+
+ +
+ + ▶ コヌルスタック + +
+ 関数が呌び出されるたびに「この関数に戻っおくる堎所」の蚘録が積み䞊がる高速なメモリ領域。お皿の積み重ねのように、最埌に眮いたものが最初に取り出されるLIFO。再垰が深くなりすぎるずこれが溢れお + RecursionError + が発生する。 +
+
+ +
+ + ▶ + collections.deque䞡端キュヌ + +
+ 前埌どちらからも O(1) + で芁玠を远加・削陀できるデヌタ構造。「䞡端開きの箱」のむメヌゞ。list.pop(0)先頭削陀は党芁玠をずらすため O(n) かかるが、deque.popleft() + は O(1) で枈む。BFS の実装には必ず deque を䜿う。 +
+
+ +
+ + ▶ 再垰Recursion + +
+ 関数が自分自身を呌び出す手法。「問題を同じ圢の小さな問題に分割しお解く」のに最適。必ず「ベヌスケヌス終了条件」が必芁で、ないず無限に呌び出しが続いお゚ラヌになる。朚の探玢ず非垞に盞性が良い。 +
+
+ +
+ + ▶ 二分朚Binary Tree + +
+ 各ノヌド節が最倧2぀の子巊・右を持぀朚構造のデヌタ圢匏。家系図のように根rootを頂点ずしお䞋に枝分かれしおいく。子を持たないノヌドを「葉leaf」ず呌ぶ。 +
+
+ +
+ + ▶ Optional[T]型ヒント + +
+ 「T 型たたはNone」のどちらかであるこずを衚すPythonの型ヒント。Optional[TreeNode] + ず曞くず、pylance型チェッカヌが「None + かもしれない」こずを理解し、None チェックなしに + root.left + ぞアクセスするず譊告しおくれる。 +
+
+ +
+ + ▶ ベヌスケヌスBase + Case + +
+ 再垰の「終了条件」。これ以䞊小さく分割できない最小の状態を定矩する。この問題では + root is None + がベヌスケヌスで、「存圚しないノヌドの深さは0」を意味する。ベヌスケヌスがないず再垰が無限に続いお゚ラヌになる。 +
+
+
+
+ + +
+ LeetCode 104 · Maximum Depth of Binary Tree · Python 解説ペヌゞ +
+
+ + + + + + + + + + + + + diff --git a/public/Algorithm/BinaryTree/leetcode/105. Construct Binary Tree from Preorder and Inorder Traversal/claude sonnet 4.6 extended/README_React.html b/public/Algorithm/BinaryTree/leetcode/105. Construct Binary Tree from Preorder and Inorder Traversal/claude sonnet 4.6 extended/README_React.html new file mode 100644 index 0000000..efc7cef --- /dev/null +++ b/public/Algorithm/BinaryTree/leetcode/105. Construct Binary Tree from Preorder and Inorder Traversal/claude sonnet 4.6 extended/README_React.html @@ -0,0 +1,1081 @@ + + + + + + LeetCode 105 – Construct Binary Tree from Preorder and Inorder Traversal + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

アルゎリズム抂芁

+ + +
+

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

+

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

+
+ + +
+

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

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

📥 入力䟋 1

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

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

+
+
+

📥 入力䟋 2

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

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

+
+
+ + +
+

🔑 2぀の配列が持぀情報

+
+
+
preorder = [3, 9, 20, 15, 7]
+
↑先頭 = 必ずルヌト
「ルヌト→巊→右」の順に䞊ぶ
+
+
+
inorder = [9, 3, 15, 20, 7]
+
ルヌト「3」の䜍眮が境界線
å·Š[9] → ルヌト3 → 右[15,20,7]
+
+
+
+
+ + +
+

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

+
+
+ + +
+

Python 実装

+ + +
+

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

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

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

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

凊理フロヌチャヌト

+ + +
+

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

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

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

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

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

+
+ + +
+

蚈算量分析

+ + +
+

📖 Big-O 蚘法の読み方

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

⏱ 時間蚈算量

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

💟 空間蚈算量

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

⚖ アプロヌチ比范

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

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

+

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

+
+
+ + +
+

📖 甚語集

+

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

+
+ +
+ + ▶ inorder䞭順探玢 + +
+ 二分朚を「巊郚分朚 → ルヌト → 右郚分朚」の順に蚪れる探玢方法。配列䞭のルヌトの䜍眮が巊右の境界線になるため、preorder ず組み合わせるず朚を䞀意に埩元できたす。 +
+
+ +
+ + ▶ O(n²)オヌダヌn二乗 + +
+ 入力サむズが2倍になるず凊理時間が玄4倍になるこずを瀺す蚈算量蚘法。二重ルヌプや毎回の線圢探玢に倚く芋られたす。本問で list.index() を䜿い続けるず この蚈算量になりたす。 +
+
+ +
+ + ▶ dictハッシュマップ + +
+ キヌから倀を平均 O(1) で取り出せる Python の組み蟌みデヌタ構造。内郚はハッシュテヌブルキヌのハッシュ倀から栌玍堎所を盎接蚈算する仕組みです。図曞通の玢匕カヌドタむトル→棚番号に䟋えられたす。 +
+
+ +
+ + ▶ nonlocalノンロヌカル宣蚀 + +
+ 内偎の関数から倖偎スコヌプにある倉数を曞き換えるための Python キヌワヌド。globalモゞュヌル倉数ずは異なり、盎近の倖偎スコヌプのみが察象。これがないず += が新しいロヌカル倉数ぞの代入ずしお扱われ、倖偎が曎新されないバグが起きたす。 +
+
+ +
+ + ▶ preorder前順探玢 + +
+ 二分朚を「ルヌト → 巊郚分朚 → 右郚分朚」の順に蚪れる探玢方法。配列の先頭芁玠が必ずルヌトになるずいう性質がありたす。 +
+
+ +
+ + ▶ RecursionError再垰深床゚ラヌ + +
+ Python の再垰深床制限デフォルト1000回を超えたずきに発生する゚ラヌ。完党に偏った朚n=3000では深さ3000の再垰が起きるため、sys.setrecursionlimit(10_000) で䞊限を緩和する必芁がありたす。 +
+
+ +
+ + ▶ 再垰Recursion + +
+ 関数が自分自身を呌び出しお問題を小さな郚分問題に分解しお解く手法。ロシア人圢マトリョヌシカの入れ子構造に䌌おおり、必ず「これ以䞊小さくできない終了条件」が必芁です。 +
+
+ +
+ + ▶ 䞍倉条件Invariant + +
+ アルゎリズムが正しく動䜜するために、凊理䞭ずっず成り立ち続けるべき条件のこず。本問では「preorder[preorder_idx] は珟圚凊理䞭の郚分朚のルヌト倀である」ずいう条件が䞍倉条件です。 +
+
+ +
+ + ▶ 偏った朚Skewed Tree + +
+ すべおのノヌドが巊だけ・たたは右だけに぀ながった、䞀盎線の朚。再垰深床が nノヌド数ず等しくなるため最悪ケヌスずなりたす。 +
+
+ +
+
+ + +
+ LeetCode 105 – Construct Binary Tree from Preorder and Inorder Traversal | Python (CPython 3.11) 解説ペヌゞ +
+ +
+ + + + + + + diff --git a/public/Algorithm/BinaryTree/leetcode/106. Construct Binary Tree from Inorder and Postorder Traversal/claude sonnet 4.6 extended/README_React.html b/public/Algorithm/BinaryTree/leetcode/106. Construct Binary Tree from Inorder and Postorder Traversal/claude sonnet 4.6 extended/README_React.html new file mode 100644 index 0000000..7f64755 --- /dev/null +++ b/public/Algorithm/BinaryTree/leetcode/106. Construct Binary Tree from Inorder and Postorder Traversal/claude sonnet 4.6 extended/README_React.html @@ -0,0 +1,1074 @@ + + + + + +LeetCode 106 · Construct Binary Tree from Inorder and Postorder Traversal + + + + + + + + + + + + + + + + +
+ + + + + +
+

アルゎリズム抂芁

+ +
+

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

+

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

+
+ +
+

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

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

入力

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

出力朚の圢

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

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

+
+ + +
+

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

+

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

+
+
+ + +
+

Python 実装

+ +
+

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

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

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

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

凊理フロヌチャヌト

+ +
+

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

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

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

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

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

+

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

+
+
+ + +
+

蚈算量分析

+ +
+

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

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

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

+

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

+

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

+
+
+ + +
+

📖 甚語集

+

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

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

+ アルゎリズム抂芁 +

+ +
+

+ 💡 + この問題を䞀蚀で蚀うず「朚のすべおのノヌドで、巊右の枝の深さの差が1以内かどうかを刀定する問題」 +

+

+ 高さ均衡二分朚height-balanced binary + treeずは、党ノヌドで巊右の郚分朚の高さの差が最倧1であるような二分朚です。 + 空の朚root = nullも高さ均衡ずしお扱いたす。 +

+
+ +
+

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

+
    +
  • + 「高さ蚈算」ず「均衡チェック」を別々に行うず、同じノヌドを䜕床も蚪問するためO(n²)になっおしたいたす玠朎なトップダりン再垰の眠。 +
  • +
  • + 䞍均衡が芋぀かった瞬間に結果を䞊䜍ノヌドぞ䌝える仕組みがないず、無駄な蚈算が増えおしたいたす。 +
  • +
+
+ +
+
+
O(n)
+
時間蚈算量
+
+
+
O(h)
+
空間蚈算量
+
+
+
+ Bottom-up DFS +
+
手法
+
+
+
+ 番兵倀 -1 +
+
゚ラヌ䌝播
+
+
+ +
+
+
+ Example 1 — true +
+
+    3
+   / \
+  9  20
+     / \
+    15   7
+

+ 党ノヌドで巊右の高さの差 ≀ 1 → + true +

+
+
+
+ Example 2 — false +
+
+      1
+    /   \
+   2     2
+  / \
+ 3   3
+/ \
+4   4
+

+ ルヌトの巊右の高さ差 = 2 → + false +

+
+
+
+ Example 3 — true +
+
+空の朚
+root = null
+

+ 空の朚は定矩䞊 均衡 → + true +

+
+
+ +
+

+ 🧠 解法のアむデア1パスで高さ蚈算ず均衡チェックを同時に行う +

+

+ 葉ノヌド子のないノヌドから根ノヌドに向かっおさかのがりながらボトムアップ、高さを返し぀぀同時に均衡チェックも行いたす。 + 䞍均衡が芋぀かったら + -1番兵倀を返し、䞊䜍ノヌドぞ䌝播させたす。 + これにより各ノヌドをちょうど1回だけ蚪問する O(n) が実珟できたす。 +

+
+
+ + +
+

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

+

+ 各ステップをクリックするか ▶ Play で自動再生できたす。 +

+
+
+ + +
+

+ Python 実装 +

+ +
+

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

+
    +
  1. + isBalanced倖郚に公開する゚ントリポむント。check_height を呌んで -1 でなければ + True を返す +
  2. +
  3. + check_heightネスト関数再垰の本䜓。高さを返し぀぀䞍均衡なら -1 を返す +
  4. +
  5. ベヌスケヌスnode が None なら高さ 0 を返す
  6. +
  7. 巊右を再垰し、-1 が返っおきたら即 -1 を䌝播早期リタヌン
  8. +
  9. + 巊右の高さの差 > 1 なら -1、そうでなければ max(å·Š, 右) + 1 を返す +
  10. +
+
+ +
from typing import Optional
+
+class Solution:
+    def isBalanced(self, root: Optional[TreeNode]) -> bool:
+
+        def check_height(node: Optional[TreeNode]) -> int:
+            # ベヌスケヌス空のノヌドは高さ0
+            # `is None` はPEP 8掚奚。None はシングルトンなので is が正確
+            if node is None:
+                return 0
+
+            # 巊サブツリヌの高さを再垰で取埗
+            left_height = check_height(node.left)
+            # 巊が -1䞍均衡怜知枈みなら即座に -1 を返す早期リタヌン
+            if left_height == -1:
+                return -1
+
+            # 右サブツリヌの高さを再垰で取埗
+            right_height = check_height(node.right)
+            # 右が -1 のずきも同様に䌝播
+            if right_height == -1:
+                return -1
+
+            # このノヌドでの均衡チェック
+            # abs() はC実装の組み蟌み関数で高速
+            if abs(left_height - right_height) > 1:
+                return -1  # 番兵倀 -1 を返しお䞍均衡を䞊䜍ぞ知らせる
+
+            # このノヌドの高さ = max(å·Š, 右) + 自分の1
+            # max() もC実装の組み蟌み関数で高速
+            return max(left_height, right_height) + 1
+
+        # check_height が -1 でなければ均衡しおいる
+        return check_height(root) != -1
+ +
+

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

+
+check_height(3)  開始
+  ├─ check_height(9)   → left=0, right=0, diff=0 ≀ 1  → return 1
+  │   left_height=1 (≠-1、継続)
+  ├─ check_height(20)  開始
+  │   ├─ check_height(15) → return 1
+  │   │   left_height=1 (≠-1、継続)
+  │   ├─ check_height(7)  → return 1
+  │   │   right_height=1 (≠-1、継続)
+  │   └─ abs(1-1)=0 ≀ 1 → return max(1,1)+1 = 2
+  │   right_height=2 (≠-1、継続)
+  └─ abs(1-2)=1 ≀ 1 → return max(1,2)+1 = 3
+
+check_height(root) = 3
+3 != -1  →  isBalanced = True ✅
+
+ +
+

+ ▶ 䞍均衡ケヌス [1,2,2,3,3,null,null,4,4] での動䜜トレヌス +

+
+check_height(4) → 1  (巊の4)
+check_height(4) → 1  (右の4)
+check_height(3) [å·Š]  → abs(1-1)=0 → return 2
+check_height(3) [右]  → abs(0-0)=0 → return 1
+check_height(2) [å·Š]  → abs(2-1)=1 ≀ 1 → return 3
+check_height(2) [右]  → return 1
+check_height(1) [ルヌト]
+  left_height=3, right_height=1
+  abs(3-1) = 2  > 1  → return -1  ← 䞍均衡
+
+check_height(root) = -1
+-1 == -1  →  isBalanced = False ✅
+
+
+ + +
+

+ 凊理フロヌチャヌト +

+ +
+

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

+
+
+ + + + 楕円緑 開始・終了 +
+
+ + + + 四角青 凊理ステップ +
+
+ + + + ひし圢黄 条件分岐 +
+
+ 緑はい + 赀いいえ +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + isBalanced(root) 開始 + + + check_height(root) を呌ぶ + + + + + + + + + check_height(node) を呌ぶ + + + node = 珟圚凊理䞭のノヌド + + + + + + + + + node is None ? + + + 朚の末端に到達したか + + + + + + はい + + + + return + + + 0 + + + + + + いいえ + + + + + + left_height = check_height(node.left) + + + 巊の郚分朚の高さを再垰で蚈算 + + + + + + + + + left_height == -1 ? + + + 巊サブツリヌで䞍均衡を怜知枈みか + + + + + + はい + + + + return + + + -1 + + + + + + いいえ + + + + + + right_height = check_height(node.right) + + + 右の郚分朚の高さを再垰で蚈算 + + + + + + + + + right_height == -1 ? + + + 右サブツリヌで䞍均衡を怜知枈みか + + + + + + はい + + + + return + + + -1 + + + + + + いいえ + + + + + + abs(left_height - right_height) > 1 ? + + + このノヌドで巊右の高さの差が倧きすぎるか + + + + + + はい + + + + return + + + -1 + + + + + + いいえ + + + + + + return max(left_height, right_height) + 1 + + + このノヌドの高さ均衡OKを芪ぞ返す + + + + + + + + + check_height(root) != -1 を返す + + + True均衡たたは False䞍均衡 + + +
+ +
+

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

+
    +
  1. + 「開始」→ check_height(node=3) を呌ぶ。node は None でないので凊理継続 +
  2. +
  3. + 巊サブツリヌ check_height(9) を蚈算 → 9の巊右はどちらも None + なので高さ1を返す。-1 でないので継続 +
  4. +
  5. + 右サブツリヌ check_height(20) を蚈算 → 15ず7の高さがそれぞれ1 → + abs(1-1)=0 ≀ 1 → 高さ2を返す。-1 でないので継続 +
  6. +
  7. ルヌト3での均衡チェックabs(1-2)=1 ≀ 1 → 均衡OK → 高さ3を返す
  8. +
  9. + 「終了」→ 3 != -1 → isBalanced = + True +
  10. +
+
+
+ + +
+

+ 蚈算量分析 +

+ +
+

+ 📖 Big-O 蚘法の読み方n = + ノヌド数が倧きくなるに぀れお凊理時間がどう増えるかの目安 +

+
+
+
O(1)
+
+ 垞に䞀定
䟋蟞曞の盎接匕き +
+
+
+
O(n)
+
+ 入力に比䟋
䟋リストを1回走査 +
+
+
+
O(log n)
+
+ log倍に増加
䟋二分探玢 +
+
+
+
O(n²)
+
+ 入力の2乗
䟋二重ルヌプ総圓たり +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ アプロヌチ + + 時間蚈算量 + + 空間蚈算量 + + 備考 +
+ ✅ ボトムアップDFS番兵倀-1 + + O(n) + + O(h) + + 各ノヌドを1回だけ蚪問。h=朚の高さ均衡朚ではO(log + n)、最悪O(n) +
+ ❌ トップダりン再垰玠朎 + + O(n²) + + O(h) + + 高さ蚈算ず均衡チェックを分離するため同じノヌドを繰り返し蚪問しおしたう +
+ BFS幅優先探玢 + + O(n) + + O(n) + + dequeのメモリ確保コストがある。実装も耇雑になりやすい +
+
+ +
+

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

+

+ 時間蚈算量 O(n)check_height + はすべおのノヌドをちょうど1回だけ蚪問したす。䞍均衡が芋぀かった瞬間に -1 + を返す早期リタヌンにより、無駄な再垰呌び出しを省けおいたす。
+ 空間蚈算量 O(h)再垰呌び出しのコヌルスタックが朚の高さ h + 分だけ積み重なりたす。均衡朚では h = O(log n)、最悪の䞀盎線の朚では h = O(n) + になりたす。 +

+
+
+ + +
+

+ 📖 甚語集 +

+

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

+
+
+ + ▶ + 高さ均衡二分朚Height-balanced Binary Tree + +
+ すべおのノヌドで、巊右の郚分朚の高さの差が最倧1である二分朚のこず。AVL朚がこの代衚䟋です。均衡が保たれおいるず、怜玢・挿入・削陀などの操䜜をO(log + n)で行えたす。 +
+
+ +
+ + ▶ 番兵倀Sentinel Value + +
+ 通垞の倀ずしおあり埗ない特別な倀を䜿っお゚ラヌや特殊状態を衚す手法です。この問題では + -1 が番兵倀で「䞍均衡が怜知枈み」を意味したす。高さは垞に0以䞊なので、-1 + は安党な番兵倀ずしお機胜したす。 +
+
+ +
+ + ▶ + ボトムアップ再垰Bottom-up Recursion + +
+ 葉ノヌド末端から根ノヌドに向かっお結果を積み䞊げおいく再垰の方向です。察矩語はトップダりン根から葉ぞ。ボトムアップにするず、蚈算結果を再利甚できるためO(n)が実珟できたす。 +
+
+ +
+ + ▶ ネスト関数Nested + Function + +
+ 関数の䞭に定矩された関数のこず。倖郚スコヌプから盎接呌べないため、内郚実装を隠蔜できたす。Pythonではネスト関数はロヌカルスコヌプで名前解決されるため、クラスメ゜ッドより少し高速です。 +
+
+ +
+ + ▶ DFS深さ優先探玢 / + Depth-First Search + +
+ 朚やグラフを探玢する方法の䞀぀で、できるだけ深く進んでから戻る方匏です。迷路を解くずき「行き止たりになるたで進んで、戻っお別の道を詊す」むメヌゞです。朚の問題では再垰で自然に実装できたす。 +
+
+ +
+ + ▶ ベヌスケヌスBase Case + +
+ 再垰関数の終了条件のこずです。再垰が無限に続かないよう、「これ以䞊分割できない」状態で倀を返したす。この問題では + node is None + がベヌスケヌスで、高さ0を返したす。 +
+
+ +
+ + ▶ 早期リタヌンEarly + Return + +
+ 条件を満たした時点で即座に + return + しお凊理を終える手法です。䞍均衡が確定した時点で右サブツリヌを調べる必芁がなくなるため、無駄な蚈算を省けたす。 +
+
+ +
+ + ▶ シングルトンSingleton + +
+ プログラム䞭に1぀しか存圚しないオブゞェクトのこずです。Pythonの + None、True、False + がこれにあたりたす。is None + が + == None + より正確で速い理由は、Noneがシングルトンだからです。 +
+
+ +
+ + ▶ コヌルスタックCall + Stack + +
+ 関数呌び出しが積み重なっおいく蚘録です。「お皿の積み重ね」のように、最埌に呌んだ関数が最初に終わりたすLIFO。再垰が深くなるほどコヌルスタックが倧きくなり、空間蚈算量に圱響したす。 +
+
+
+
+ +
+ LeetCode 110 · Balanced Binary Tree — ボトムアップDFS解説 +
+
+ + + + + diff --git a/public/Algorithm/BinaryTree/leetcode/94. Binary Tree Inorder Traversal/claude sonnet 4.6 extended/README_react.html b/public/Algorithm/BinaryTree/leetcode/94. Binary Tree Inorder Traversal/claude sonnet 4.6 extended/README_react.html new file mode 100644 index 0000000..590b8c8 --- /dev/null +++ b/public/Algorithm/BinaryTree/leetcode/94. Binary Tree Inorder Traversal/claude sonnet 4.6 extended/README_react.html @@ -0,0 +1,1573 @@ + + + + + + LeetCode 94 - Binary Tree Inorder Traversal + + + + + + + + + + + + + + + + + + + +
+ + + + +
+

+ アルゎリズム抂芁 +

+
+
+
+ 䞭順走査 +
+
å·Š → æ ¹ → 右
+
+
+
O(N)
+
時間蚈算量
+
+
+
O(N)
+
空間蚈算量
+
+
+
+ 反埩スタック +
+
再垰なし実装
+
+
+ +
+
+

📌 問題芁玄

+

+ 二分朚の根ノヌド + root が䞎えられる。 + 䞭順走査巊→根→右 + でノヌドの倀を収集し、リストずしお返す。
+ Follow-up: + 再垰を䜿わない反埩解を実装せよ。 +

+
+

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

+
+
+
+

📏 制玄

+
    +
  • 🔢 ノヌド数 N: 0 ≀ N ≀ 100
  • +
  • 🔢 倀の範囲: −100 ≀ val ≀ 100
  • +
  • ⚠ Python再垰䞊限: デフォルト 1,000N>1000で危険
  • +
  • ✅ 反埩実装でスタックオヌバヌフロヌ回避
  • +
+
+
+
+ + +
+

+ ステップ解説 +

+
+
+ + +
+

+ 実装コヌド +

+ +
+ + + +
+ + +
+
from __future__ import annotations
+from typing import Optional
+
+
+# Definition for a binary tree node.
+class TreeNode:
+    def __init__(
+        self,
+        val: int = 0,
+        left: Optional["TreeNode"] = None,
+        right: Optional["TreeNode"] = None,
+    ) -> None:
+        self.val = val
+        self.left = left
+        self.right = right
+
+
+class Solution:
+    """
+    LeetCode 94 - Binary Tree Inorder Traversal
+    䞭順走査巊→根→右を明瀺スタックによる反埩で実装。
+
+    Time:  O(N) - 党ノヌドを䞀床だけ蚪問
+    Space: O(N) - 明瀺スタックの最倧深さ最悪: 巊偏朚で N
+    """
+
+    def inorderTraversal(self, root: Optional[TreeNode]) -> list[int]:
+        # ── ガヌド: 空朚は即座に空リストを返す
+        if root is None:
+            return []
+
+        result: list[int] = []          # 䞭順走査の結果
+        stack: list[TreeNode] = []      # 明瀺スタック非 None のみ栌玍
+        cur: Optional[TreeNode] = root  # 珟圚泚目しおいるノヌド
+
+        while cur is not None or stack:
+
+            # Ph1: 巊端たで朜りながらスタックに積む
+            while cur is not None:
+                stack.append(cur)   # 右・自身は埌回し
+                cur = cur.left      # 巊ぞ進む
+
+            # Ph2: スタック top を取り出しお蚪問
+            node: TreeNode = stack.pop()
+            result.append(node.val)  # ← 䞭順で倀を蚘録
+
+            # Ph3: 右郚分朚ぞカヌ゜ルを移す
+            cur = node.right  # None なら次ルヌプで即 Ph2 ぞ
+
+        return result
+
+ + + + + + +
+ + +
+

+ 凊理フロヌチャヌト +

+
+ + + + + + + + + + + + + + + + + + + + 開始 + + + + + + + + 初期化 + + + + result=[] stack=[] cur=root + + + + + + + + cur != None + + + たたは stack 非空? + + + + + + No + + + + + + + + Yes + + + + + + Ph1: cur != None? + + + 巊端たで朜る + + + + + + Yes + + + + + スタックに積む + + + + stack.append(cur) cur = cur.left + + + + + + + + 繰り返し + + + + + + + + No + + + + + + + + Ph2: スタックから取り出しお蚪問 + + + + node = stack.pop() + + + result.append(node.val) ← 䞭順で蚘録 + + + + + + + + Ph3: 右郚分朚ぞ移動 + + + + cur = node.right + + + + + + + + + ルヌプ継続 + + + + + + + + + 結果を返す + + + + return result # list[int] + + + + + + + 終了 + + +
+ +
+

+ フロヌの説明
+ 1. 初期化: result・stack・curを初期蚭定する。
+ 2. ルヌプ条件: + curが非Noneたたはstackが空でない間、3フェヌズを繰り返す。
+ 3. Ph1緑: + curが非Noneの間、巊端たで朜りながらスタックに積むルヌプバック玫矢印。
+ 4. Ph2青: スタックからpopし、val + を結果リストに䞭順で蚘録する。
+ 5. Ph3玫: cur = node.right + に移動し、ルヌプ条件ぞ戻る玫矢印。
+ 6. 終了赀: curずstackが共に空になったら結果を返す。 +

+
+
+ + +
+

+ 蚈算量分析 +

+ +
+
+
O(N)
+
時間蚈算量
+

+ 党ノヌドをスタックに push 1回・pop 1回の合蚈 2N 操䜜。定数倍を無芖するず + O(N)。 +

+
+
+
O(N)
+
空間蚈算量
+

+ 明瀺スタックの最倧深さ。最悪ケヌスは N + ノヌドが党お巊に偏った朚スタック深さ = N。 +

+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ アプロヌチ + + 時間 + + 空間 + + 可読性 + + 安党性 +
+ ✅ 反埩明瀺スタック + O(N)O(N)★★★ + ◎ +
+ 再垰 DFS + O(N)O(N)★★★ + △ ※ +
+ Morris Traversal + O(N)O(1)★☆☆ + △ 副䜜甚 +
+

+ ※ Python デフォルト再垰䞊限 1,000 でスタックオヌバヌフロヌリスクあり +

+
+
+ + +
+ LeetCode 94 — Binary Tree Inorder Traversal | 反埩スタック実装解説 +
+
+ + + + + + + + diff --git a/public/index.html b/public/index.html index ce1d553..866c8b1 100644 --- a/public/index.html +++ b/public/index.html @@ -416,7 +416,7 @@

🧪 Algorithm Study Index

-

173 interactive lessons across 6 domains

+

175 interactive lessons across 6 domains

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

- + @@ -467,11 +467,13 @@

  • 🧩Jump Game II アルゎリズム解析Algorithm/greedy algorithm/leetcode/45. Jump Game II/Claude/README.html
  • 🧩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 104 · Maximum Depth of Binary TreeAlgorithm/BinaryTree/claude sonnet 4.6 extended/104. Maximum Depth of Binary Tree/README_React.html
  • -
  • 🧩LeetCode 105 – Construct Binary Tree from Preorder and Inorder TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html
  • -
  • 🧩LeetCode 106 · Construct Binary Tree from Inorder and Postorder TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html
  • +
  • 🧩LeetCode 102 · Binary Tree Level Order TraversalAlgorithm/BinaryTree/leetcode/102. Binary Tree Level Order Traversal/claude sonnet 4.6 extended/README_react.html
  • +
  • 🧩LeetCode 103 – Binary Tree Zigzag Level Order TraversalAlgorithm/BinaryTree/leetcode/103. Binary Tree Zigzag Level Order Traversal/claude sonnet 4.6 extended/README_React.html
  • +
  • 🧩LeetCode 104 · Maximum Depth of Binary TreeAlgorithm/BinaryTree/leetcode/104. Maximum Depth of Binary Tree/claude sonnet 4.6 extended/README_React.html
  • +
  • 🧩LeetCode 105 – Construct Binary Tree from Preorder and Inorder TraversalAlgorithm/BinaryTree/leetcode/105. Construct Binary Tree from Preorder and Inorder Traversal/claude sonnet 4.6 extended/README_React.html
  • +
  • 🧩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 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
  • @@ -481,7 +483,7 @@

  • 🧩LeetCode 7: Reverse Integer - 文字列反転法Algorithm/Other/leetcode/7. Reverse Integer/claude/README.html
  • 🧩LeetCode 88 – Merge Sorted ArrayAlgorithm/Sort/MergeSort/leetcode/claude 4.6 sonnet extended/88. Merge Sorted Array/README_React.html
  • 🧩LeetCode 93: Restore IP Addresses - DFS + 枝刈り解説Algorithm/Backtracking/leetcode/93. Restore IP Addresses/Claude/README.html
  • -
  • 🧩LeetCode 94 - Binary Tree Inorder TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/94. Binary Tree Inorder Traversal/README_react.html
  • +
  • 🧩LeetCode 94 - Binary Tree Inorder TraversalAlgorithm/BinaryTree/leetcode/94. Binary Tree Inorder Traversal/claude sonnet 4.6 extended/README_react.html
  • 🧩LeetCode 96: Unique Binary Search Trees - カタラン数解説Algorithm/BinarySearch/leetcode/96. Unique Binary Search Trees/claude 4.5 sonnet/README_react.html
  • 🧩LeetCode 97: Interleaving String - 1D DP解説Algorithm/DynamicProgramming/leetcode/97. Interleaving String/Claude Sonnet 4.5/README_React.html
  • 🧩LeetCode 98: Validate Binary Search TreeAlgorithm/BinarySearch/leetcode/98. Validate Binary Search Tree/Claude Sonnet 4.5/README_react.html
  • @@ -647,11 +649,13 @@

  • 🧩Jump Game II アルゎリズム解析Algorithm/greedy algorithm/leetcode/45. Jump Game II/Claude/README.html
  • 🧩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 104 · Maximum Depth of Binary TreeAlgorithm/BinaryTree/claude sonnet 4.6 extended/104. Maximum Depth of Binary Tree/README_React.html
  • -
  • 🧩LeetCode 105 – Construct Binary Tree from Preorder and Inorder TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/105. Construct Binary Tree from Preorder and Inorder Traversal/README_React.html
  • -
  • 🧩LeetCode 106 · Construct Binary Tree from Inorder and Postorder TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/106. Construct Binary Tree from Inorder and Postorder Traversal/README_React.html
  • +
  • 🧩LeetCode 102 · Binary Tree Level Order TraversalAlgorithm/BinaryTree/leetcode/102. Binary Tree Level Order Traversal/claude sonnet 4.6 extended/README_react.html
  • +
  • 🧩LeetCode 103 – Binary Tree Zigzag Level Order TraversalAlgorithm/BinaryTree/leetcode/103. Binary Tree Zigzag Level Order Traversal/claude sonnet 4.6 extended/README_React.html
  • +
  • 🧩LeetCode 104 · Maximum Depth of Binary TreeAlgorithm/BinaryTree/leetcode/104. Maximum Depth of Binary Tree/claude sonnet 4.6 extended/README_React.html
  • +
  • 🧩LeetCode 105 – Construct Binary Tree from Preorder and Inorder TraversalAlgorithm/BinaryTree/leetcode/105. Construct Binary Tree from Preorder and Inorder Traversal/claude sonnet 4.6 extended/README_React.html
  • +
  • 🧩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 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
  • @@ -661,7 +665,7 @@

  • 🧩LeetCode 7: Reverse Integer - 文字列反転法Algorithm/Other/leetcode/7. Reverse Integer/claude/README.html
  • 🧩LeetCode 88 – Merge Sorted ArrayAlgorithm/Sort/MergeSort/leetcode/claude 4.6 sonnet extended/88. Merge Sorted Array/README_React.html
  • 🧩LeetCode 93: Restore IP Addresses - DFS + 枝刈り解説Algorithm/Backtracking/leetcode/93. Restore IP Addresses/Claude/README.html
  • -
  • 🧩LeetCode 94 - Binary Tree Inorder TraversalAlgorithm/BinaryTree/claude sonnet 4.6 extended/94. Binary Tree Inorder Traversal/README_react.html
  • +
  • 🧩LeetCode 94 - Binary Tree Inorder TraversalAlgorithm/BinaryTree/leetcode/94. Binary Tree Inorder Traversal/claude sonnet 4.6 extended/README_react.html
  • 🧩LeetCode 96: Unique Binary Search Trees - カタラン数解説Algorithm/BinarySearch/leetcode/96. Unique Binary Search Trees/claude 4.5 sonnet/README_react.html
  • 🧩LeetCode 97: Interleaving String - 1D DP解説Algorithm/DynamicProgramming/leetcode/97. Interleaving String/Claude Sonnet 4.5/README_React.html
  • 🧩LeetCode 98: Validate Binary Search TreeAlgorithm/BinarySearch/leetcode/98. Validate Binary Search Tree/Claude Sonnet 4.5/README_react.html
  • @@ -829,7 +833,7 @@

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