diff --git a/Algorithm/Backtracking/leetcode/52. N-Queens ll/GPT/README.html b/Algorithm/Backtracking/leetcode/52. N-Queens ll/GPT/README.html index a4fe813b..6fa294ed 100644 --- a/Algorithm/Backtracking/leetcode/52. N-Queens ll/GPT/README.html +++ b/Algorithm/Backtracking/leetcode/52. N-Queens ll/GPT/README.html @@ -503,6 +503,9 @@

🎮 インタラクティブデモ

+ diff --git a/Algorithm/BinarySearch/leetcode/4. Median of Two Sorted Arrays/Claude/README.html b/Algorithm/BinarySearch/leetcode/4. Median of Two Sorted Arrays/Claude/README.html index b54adfdc..33d6804c 100644 --- a/Algorithm/BinarySearch/leetcode/4. Median of Two Sorted Arrays/Claude/README.html +++ b/Algorithm/BinarySearch/leetcode/4. Median of Two Sorted Arrays/Claude/README.html @@ -664,6 +664,16 @@

最適化の比較

+ diff --git a/Algorithm/BinarySearch/leetcode/95. Unique Binary Search Trees II/Claude/README.html b/Algorithm/BinarySearch/leetcode/95. Unique Binary Search Trees II/Claude/README.html index daa0c2c7..e1f600a8 100644 --- a/Algorithm/BinarySearch/leetcode/95. Unique Binary Search Trees II/Claude/README.html +++ b/Algorithm/BinarySearch/leetcode/95. Unique Binary Search Trees II/Claude/README.html @@ -766,6 +766,16 @@

💾 空間計算量

+ diff --git a/Algorithm/BinarySearch/leetcode/98. Validate Binary Search Tree/Claude Sonnet 4.5/README_react.html b/Algorithm/BinarySearch/leetcode/98. Validate Binary Search Tree/Claude Sonnet 4.5/README_react.html index 8caabde0..b689d5d5 100644 --- a/Algorithm/BinarySearch/leetcode/98. Validate Binary Search Tree/Claude Sonnet 4.5/README_react.html +++ b/Algorithm/BinarySearch/leetcode/98. Validate Binary Search Tree/Claude Sonnet 4.5/README_react.html @@ -913,6 +913,16 @@

代替手法との比 + diff --git a/Algorithm/BinarySearch/leetcode/99. Recover Binary Search Tree/Claude Opus 4.5/README_react.html b/Algorithm/BinarySearch/leetcode/99. Recover Binary Search Tree/Claude Opus 4.5/README_react.html index 79b3c9c8..ef14f291 100644 --- a/Algorithm/BinarySearch/leetcode/99. Recover Binary Search Tree/Claude Opus 4.5/README_react.html +++ b/Algorithm/BinarySearch/leetcode/99. Recover Binary Search Tree/Claude Opus 4.5/README_react.html @@ -968,6 +968,16 @@

詳細分析

+ diff --git a/Algorithm/DynamicProgramming/leetcode/63. Unique Paths II/Claude/README.html b/Algorithm/DynamicProgramming/leetcode/63. Unique Paths II/Claude/README.html index e2b71be0..1c27703a 100644 --- a/Algorithm/DynamicProgramming/leetcode/63. Unique Paths II/Claude/README.html +++ b/Algorithm/DynamicProgramming/leetcode/63. Unique Paths II/Claude/README.html @@ -1402,6 +1402,16 @@

+ @@ -1847,7 +1857,7 @@

// Initialize Prism.js with proper configuration if (typeof Prism !== 'undefined') { Prism.plugins.autoloader.languages_path = - 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/'; + '/vendor/prismjs/components/'; // Custom copy button text if (Prism.plugins.toolbar) { diff --git a/Algorithm/DynamicProgramming/leetcode/64. Minimum Path Sum/Claude/README.html b/Algorithm/DynamicProgramming/leetcode/64. Minimum Path Sum/Claude/README.html index 521a2cbf..0695be6b 100644 --- a/Algorithm/DynamicProgramming/leetcode/64. Minimum Path Sum/Claude/README.html +++ b/Algorithm/DynamicProgramming/leetcode/64. Minimum Path Sum/Claude/README.html @@ -226,6 +226,14 @@ } } + diff --git a/Algorithm/DynamicProgramming/leetcode/91. Decode Ways/Claude/README.html b/Algorithm/DynamicProgramming/leetcode/91. Decode Ways/Claude/README.html index 07be8439..1aea4585 100644 --- a/Algorithm/DynamicProgramming/leetcode/91. Decode Ways/Claude/README.html +++ b/Algorithm/DynamicProgramming/leetcode/91. Decode Ways/Claude/README.html @@ -842,6 +842,16 @@

+ diff --git a/Algorithm/DynamicProgramming/leetcode/91. Decode Ways/Claude/README_react.html b/Algorithm/DynamicProgramming/leetcode/91. Decode Ways/Claude/README_react.html index 29a830c7..3556d442 100644 --- a/Algorithm/DynamicProgramming/leetcode/91. Decode Ways/Claude/README_react.html +++ b/Algorithm/DynamicProgramming/leetcode/91. Decode Ways/Claude/README_react.html @@ -933,6 +933,16 @@

📋 アプローチ比較

+ diff --git a/Algorithm/DynamicProgramming/other/Longest-common subsequence problem/Claude/README.html b/Algorithm/DynamicProgramming/other/Longest-common subsequence problem/Claude/README.html index 07c1b6ea..5db187ea 100644 --- a/Algorithm/DynamicProgramming/other/Longest-common subsequence problem/Claude/README.html +++ b/Algorithm/DynamicProgramming/other/Longest-common subsequence problem/Claude/README.html @@ -288,6 +288,14 @@ } } + @@ -439,6 +447,9 @@

🎯 3つのDP手法比較

+ + diff --git a/Algorithm/Other/leetcode/6. Zigzag Conversion/Claude/README.html b/Algorithm/Other/leetcode/6. Zigzag Conversion/Claude/README.html index dd2e8af3..71b1dcee 100644 --- a/Algorithm/Other/leetcode/6. Zigzag Conversion/Claude/README.html +++ b/Algorithm/Other/leetcode/6. Zigzag Conversion/Claude/README.html @@ -864,6 +864,16 @@

代替手法との比 + diff --git a/Algorithm/Other/leetcode/7. Reverse Integer/claude/README.html b/Algorithm/Other/leetcode/7. Reverse Integer/claude/README.html index 40030fe3..00bd552a 100644 --- a/Algorithm/Other/leetcode/7. Reverse Integer/claude/README.html +++ b/Algorithm/Other/leetcode/7. Reverse Integer/claude/README.html @@ -691,6 +691,17 @@

手法比較

+ + diff --git a/Algorithm/Other/leetcode/82. Remove Duplicates from Sorted List II/Claude/README.html b/Algorithm/Other/leetcode/82. Remove Duplicates from Sorted List II/Claude/README.html index 323f4c23..258939d5 100644 --- a/Algorithm/Other/leetcode/82. Remove Duplicates from Sorted List II/Claude/README.html +++ b/Algorithm/Other/leetcode/82. Remove Duplicates from Sorted List II/Claude/README.html @@ -864,6 +864,9 @@

パフォーマンス特性

+ + + + + + + + + + + + + + + + + + + +
+ + + + +
+

+ アルゴリズム概要 +

+ +
+
+
O(n)
+
時間計算量
+
+
+
O(1)
+
空間計算量
+
+
+
+ 0 〜 300 +
+
ノード数制約
+
+
+
+ -100〜100 +
+
値の範囲
+
+
+ +
+

問題の要点

+

+ ソート済み単方向連結リストの先頭ノード + head + を受け取り、 各要素がちょうど 1 回だけ現れるようにリストを変更して返す。
+ ソート済みであるという特性から、重複は必ず隣接して現れる。 これにより 1 + パスの線形走査で解決できる。 +

+
+ +
+
+
入力例 1
+
head = [1, 1, 2]
+
出力: [1, 2]
+
+
+
入力例 2
+
head = [1, 1, 2, 3, 3]
+
出力: [1, 2, 3]
+
+
+ +
+
⚠️ 落とし穴
+
    +
  • + 🔸 重複スキップ後に + current + を進めてはいけない(3連続重複を見逃す) +
  • +
  • + 🔸 head is None と + head.next is None + の両方をガード +
  • +
  • 🔸 新しいノードを作成しない — インプレースでポインタだけ付け替える
  • +
+
+
+ + +
+

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

+
+
+ + +
+

+ 実装コード +

+
+
+ + +
+

+ 処理フローチャート +

+ + +
+
+ 開始 / 終了 +
+
+ 処理ノード +
+
+ 条件分岐 +
+
+ はい / 正常終了 +
+
+ 重複検出 +
+
+ ループバック +
+
+ +
+
+ flowchart TD + Start([" 開始 "]) + Guard["ガード節
head is None OR head.next is None ?"] + GuardTrue["return head
変更なしで即時返却"] + Init["初期化
current = head"] + LoopCheck{"current.next
is not None ?"} + Cache["nxt = current.next
次ノードをキャッシュ"] + DupCheck{"current.val
== nxt.val ?"} + Skip["nxt をスキップ
current.next = nxt.next
※ current は動かさない"] + Advance["current を前進
current = nxt"] + Return["return head
重複除去済みリストを返す"] + End([" 終了 "]) + + Start --> Guard + Guard -- "True
空 or 単一ノード" --> GuardTrue + Guard -- "False
複数ノード存在" --> Init + GuardTrue --> End + Init --> LoopCheck + LoopCheck -- "False
current.next が None
ループ終了" --> Return + LoopCheck -- "True
次ノード存在" --> Cache + Cache --> DupCheck + DupCheck -- "True
重複あり" --> Skip + DupCheck -- "False
重複なし" --> Advance + Skip -- "再チェック
同じ current で
ループ先頭へ戻る" --> LoopCheck + Advance -- "次ノードへ
ループ先頭へ戻る" --> LoopCheck + Return --> End + + style Start fill:#d1fae5,stroke:#10b981,stroke-width:2px,color:#065f46 + style End fill:#d1fae5,stroke:#10b981,stroke-width:2px,color:#065f46 + style Guard fill:#e0f2fe,stroke:#0284c7,stroke-width:2px,color:#0c4a6e + style GuardTrue fill:#d1fae5,stroke:#059669,stroke-width:2px,color:#065f46 + style Init fill:#e0f2fe,stroke:#0284c7,stroke-width:2px,color:#0c4a6e + style LoopCheck fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#92400e + style Cache fill:#f1f5f9,stroke:#64748b,stroke-width:2px,color:#1e293b + style DupCheck fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#92400e + style Skip fill:#fee2e2,stroke:#dc2626,stroke-width:2px,color:#991b1b + style Advance fill:#f1f5f9,stroke:#64748b,stroke-width:2px,color:#1e293b + style Return fill:#d1fae5,stroke:#059669,stroke-width:2.5px,color:#065f46 + + linkStyle 0 stroke:#64748b,stroke-width:2px + linkStyle 1 stroke:#059669,stroke-width:2px + linkStyle 2 stroke:#64748b,stroke-width:2px + linkStyle 3 stroke:#059669,stroke-width:2px + linkStyle 4 stroke:#64748b,stroke-width:2px + linkStyle 5 stroke:#059669,stroke-width:2px + linkStyle 6 stroke:#64748b,stroke-width:2px + linkStyle 7 stroke:#64748b,stroke-width:2px + linkStyle 8 stroke:#dc2626,stroke-width:2px + linkStyle 9 stroke:#64748b,stroke-width:2px + linkStyle 10 stroke:#a855f7,stroke-width:2px,stroke-dasharray:6 4 + linkStyle 11 stroke:#a855f7,stroke-width:2px,stroke-dasharray:6 4 + linkStyle 12 stroke:#059669,stroke-width:2px +
+
+ + +
+
+
+ ① ガード節(Guard) +
+

+ リストが空(None)、またはノードが1つ(head.next is None)なら重複は存在しない。head を返して終了(緑の矢印)。 +

+
+
+
+ ② ループ条件チェック +
+

+ current.next is None + になったらループ終了(緑矢印 → return)。
current.next + が存在する間は内部処理を継続(下方向)。 +

+
+
+
+ ③ 重複検出 → Skip(赤矢印) +
+

+ current.val == nxt.val なら + current.next = nxt.next で + nxt を切り離す。current は移動せず、ループ先頭へ戻って再チェック(紫の破線)。 +

+
+
+
+ ④ 値が異なる → Advance(紫破線) +
+

+ current.val != nxt.val なら + current = nxt + で1つ前進。ループ先頭へ戻って次のノードを比較(紫の破線)。 +

+
+
+
+ + +
+

+ 計算量分析 +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ 指標 + + 値 + + 理由 +
+ 時間計算量 + + O(n) + + 各ノードを最大 1 回走査。重複スキップ時も + current は移動しないが、next + の参照が前進するため全体では O(n) +
+ 空間計算量 + + O(1) + + スタック変数 current / + nxt のみ。新規ノード生成ゼロ +
+ ヒープ確保 + + 0 回 + + 既存ノードの + next + 付け替えのみ。新オブジェクト生成なし +
+
+ +
+

アプローチ比較

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ アプローチ + + Time + + Space + + 特徴 +
+ ✅ 1ポインタ・インプレース(本実装) + + O(n) + + O(1) + + 最適。ヒープ確保ゼロ +
+ 再帰 + + O(n) + + O(n) + + 可読性高いがコールスタック消費 +
+ 配列変換+再構築 + + O(n) + + O(n) + + 不要なオブジェクト生成多数 +
+
+
+
+ + + + + + + + diff --git a/Algorithm/Other/leetcode/83. Remove Duplicates from Sorted List/Claude 4.6 extended/Remove_Duplicates_from_Sorted_List_Python.md b/Algorithm/Other/leetcode/83. Remove Duplicates from Sorted List/Claude 4.6 extended/Remove_Duplicates_from_Sorted_List_Python.md new file mode 100644 index 00000000..166f5c71 --- /dev/null +++ b/Algorithm/Other/leetcode/83. Remove Duplicates from Sorted List/Claude 4.6 extended/Remove_Duplicates_from_Sorted_List_Python.md @@ -0,0 +1,191 @@ +# LeetCode #83 - Remove Duplicates from Sorted List (Python) + +--- + +## 1. 問題分析結果 + +### 競技プログラミング視点 + +- **制約分析**: `n ≤ 300` と極小 → アルゴリズムより**ポインタ操作の正確性**が支配的 +- **最速手法**: 1ポインタ線形走査 `O(n)` / 追加メモリなし `O(1)` +- **メモリ最小化**: インプレース `next` 付け替えのみ → 新規オブジェクト生成ゼロ +- **CPython最適化**: 属性アクセス(`obj.attr`)はCPythonでコスト高 → ローカル変数へキャッシュ + +### 業務開発視点 + +- **型安全設計**: `Optional[ListNode]` を厳密に使い、Pylance エラーゼロを確保 +- **エラーハンドリング**: `head is None` / `head.next is None` をガード節で明示 +- **可読性**: ステップごとにコメントを付与し、意図を明示 + +### Python特有分析 + +- **データ構造**: 連結リストのノードは `ListNode` クラス → Python オブジェクト参照で管理 +- **標準ライブラリ**: 本問題では不要(ポインタ操作のみ) +- **CPython最適化**: `current.next` の繰り返しアクセスを `nxt` ローカル変数でキャッシュ → LOAD_ATTR 削減 + +--- + +## 2. アプローチ比較 + +| アプローチ | 時間計算量 | 空間計算量 | Python実装コスト | 可読性 | CPython最適化 | 備考 | +| --------------------------- | ---------- | ---------- | ---------------- | ------ | ------------- | --------------------------- | +| **1ポインタ・インプレース** | O(n) | O(1) | 低 | ★★★ | 適 | ✅ 最適解 | +| 再帰 | O(n) | O(n) | 低 | ★★★ | 不適 | スタック消費・n≤300なら許容 | +| 配列変換+再構築 | O(n) | O(n) | 中 | ★★☆ | 不適 | 不要なオブジェクト生成 | + +--- + +## 3. 採用アルゴリズムと根拠 + +- **選択**: 1ポインタ・インプレース走査 +- **理由**: ソート済みという特性上、重複は**必ず隣接**するため1パスで完結。`O(1)` 追加メモリで最適 +- **Python最適化戦略**: `current.next` の属性アクセスをローカル変数 `nxt` にキャッシュし LOAD_ATTR を削減 +- **トレードオフ**: 競技版は型チェック省略で最速、業務版は Pylance 対応の型安全を優先 + +--- + +## 4. 実装 + +```python +# Runtime 0 ms +# Beats 100.00% +# Memory 19.30 MB +# Beats 91.01% +from typing import Optional + + +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val: int = 0, next: Optional['ListNode'] = None) -> None: +# self.val = val +# self.next = next + + +class Solution: + """ + LeetCode #83 - Remove Duplicates from Sorted List + + ソート済み連結リストから重複ノードをインプレースで削除する。 + 業務開発版(型安全・Pylance対応)と + 競技プログラミング版(最速・最小)の2パターンを提供。 + """ + + # ------------------------------------------------------------------ # + # 業務開発版 ── 型安全・可読性・Pylance 対応 # + # ------------------------------------------------------------------ # + def deleteDuplicates(self, head: Optional['ListNode']) -> Optional['ListNode']: + """ + ソート済み連結リストの重複ノードを削除する(業務開発版) + + Args: + head: 連結リストの先頭ノード(空リストの場合は None) + + Returns: + 重複を除いたソート済み連結リストの先頭ノード + + Time Complexity: O(n) ─ 各ノードを最大1回走査 + Space Complexity: O(1) ─ ポインタ変数のみ、追加メモリなし + """ + # ── ガード節 ──────────────────────────────────────────────────── + # 空リスト、またはノードが1つ → 重複なし、そのまま返す + if head is None or head.next is None: + return head + + # ── 1ポインタ走査(インプレース) ───────────────────────────── + current: ListNode = head # type: ignore[name-defined] + + while current.next is not None: + nxt: ListNode = current.next # type: ignore[name-defined] + # ┌──────────────────────────────────────────────┐ + # │ 重複検出: current.val == nxt.val │ + # │ │ + # │ [1] → [1] → [2] │ + # │ ↑ ↑ │ + # │ cur nxt (スキップ対象) │ + # │ │ + # │ [1] ──────────→ [2] ← nxt.next を接続 │ + # └──────────────────────────────────────────────┘ + if current.val == nxt.val: + # 重複 → nxt をスキップ(current は進めない) + # 次のノードも同値の可能性があるため + current.next = nxt.next + else: + # 異なる値 → current を1つ進める + current = nxt + + return head + + # ------------------------------------------------------------------ # + # 競技プログラミング版 ── 最速・型チェック省略 # + # ------------------------------------------------------------------ # + def deleteDuplicates_competitive( + self, head: Optional['ListNode'] + ) -> Optional['ListNode']: + """ + 競技プログラミング向け最適化実装 + + - エラーハンドリング省略 + - ローカル変数キャッシュで LOAD_ATTR を削減 + - CPython の属性参照コストを最小化 + + Time Complexity: O(n) + Space Complexity: O(1) + """ + cur = head + while cur and cur.next: + # cur.next を nxt にキャッシュ → LOAD_ATTR 削減 + nxt = cur.next + if cur.val == nxt.val: + cur.next = nxt.next # スキップ(cur は移動しない) + else: + cur = nxt # 前進 + return head +``` + +--- + +## 5. ポインタ操作の可視化 + +``` +【入力】 head = [1, 1, 2, 3, 3] + +Step 1 cur.val(1) == nxt.val(1) → nxt をスキップ + [1] → [1] → [2] → [3] → [3] → None + ↑ + cur + ↓ cur.next = nxt.next + [1] ──────→ [2] → [3] → [3] → None + ↑ + cur ※ cur は移動しない(次も重複の可能性) + +Step 2 cur.val(1) != nxt.val(2) → cur を前進 + [1] → [2] → [3] → [3] → None + ↑ + cur + +Step 3 cur.val(2) != nxt.val(3) → cur を前進 + [1] → [2] → [3] → [3] → None + ↑ + cur + +Step 4 cur.val(3) == nxt.val(3) → nxt をスキップ + [1] → [2] → [3] → None + ↑ + cur + +Step 5 cur.next is None → ループ終了 + +【出力】 [1, 2, 3] ✅ +``` + +--- + +## 6. 計算量サマリー + +| 指標 | 値 | 説明 | +| --------------- | ------ | ----------------------------------------- | +| **時間計算量** | `O(n)` | 各ノードを最大1回走査 | +| **空間計算量** | `O(1)` | ローカル変数のみ、追加構造なし | +| **安定性** | ✅ | 元の順序・値を保持 | +| **破壊的操作** | ✅ | 元リストをインプレースで変更 | +| **Pylance対応** | ✅ | `Optional[ListNode]` で静的解析エラーなし | diff --git a/Algorithm/Other/leetcode/83. Remove Duplicates from Sorted List/Claude 4.6 extended/Remove_Duplicates_from_Sorted_List_Rust.md b/Algorithm/Other/leetcode/83. Remove Duplicates from Sorted List/Claude 4.6 extended/Remove_Duplicates_from_Sorted_List_Rust.md new file mode 100644 index 00000000..d97f7598 --- /dev/null +++ b/Algorithm/Other/leetcode/83. Remove Duplicates from Sorted List/Claude 4.6 extended/Remove_Duplicates_from_Sorted_List_Rust.md @@ -0,0 +1,190 @@ +# LeetCode #83 - Remove Duplicates from Sorted List (Rust) + +--- + +## 1. 問題の分析 + +### 競技プログラミング視点 + +- **制約分析**: `n ≤ 300` → アルゴリズムより**所有権モデルとの格闘**が主戦場 +- **最速手法**: 1ポインタ線形走査 `O(n)` / 追加ヒープアロケーションゼロ `O(1)` +- **メモリ最小化**: `Box` の drop を `take()` で制御し、不要ノードを即座に解放 + +### 業務開発視点 + +- **型安全設計**: `Option>` が Rust での連結リスト表現 → `None` = リスト終端が型レベルで保証 +- **エラーハンドリング**: `Option` の `map_or` / `take` で null 相当の安全な操作 +- **所有権設計**: 関数が `head` の所有権を受け取り、変更済みリストの所有権を返す + +### Rust特有の考慮点 + +- `Option>` の二重ラップ → `as_mut()` / `take()` / `.next` の連鎖が肝 +- **借用チェッカーとの戦い**: `current` への `&mut` を保持しつつ `node.next` を書き換える → `while let` ループで解決 +- スタック上の `current: Option<&mut Box>` のみ → ヒープ追加確保ゼロ + +--- + +## 2. アルゴリズムアプローチ比較 + +| アプローチ | 時間計算量 | 空間計算量 | Rust実装コスト | 安全性 | 可読性 | 備考 | +| --------------------------- | ---------- | ---------- | -------------- | ------ | ------ | ------------------------ | +| **1ポインタ・インプレース** | O(n) | O(1) | 中 | 高 | 高 | ✅ 最適解・追加alloc不要 | +| 再帰 | O(n) | O(n) | 低 | 高 | 高 | スタック消費・TCO非保証 | +| Vec収集+再構築 | O(n) | O(n) | 低 | 高 | 中 | 不要なヒープ確保 | + +--- + +## 3. 選択したアルゴリズムと理由 + +- **選択**: 1ポインタ・インプレース走査 +- **理由**: + - ソート済みリストの隣接重複という特性で1パス完結 + - `Box` の所有権移動を `take()` で明示的に制御 → 解放タイミングが明確 + - 再帰は末尾呼び出し最適化が Rust でコンパイラ保証されないため回避 +- **Rust固有の最適化ポイント**: + - `take()` で `next` の所有権を一時取り出し → 借用チェッカーを満足させる慣用パターン + - `as_mut()` で `Option>` を `Option<&mut Box>` に変換 → ゼロコスト + - スタック変数 `current` のみ → キャッシュフレンドリー + +--- + +## 4. 実装コード + +```rust +// Runtime 0 ms +// Beats 100.00% +// Memory 2.13 MB +// Beats 68.10% +// Definition for singly-linked list. +// #[derive(PartialEq, Eq, Clone, Debug)] +// pub struct ListNode { +// pub val: i32, +// pub next: Option> +// } +// +// impl ListNode { +// #[inline] +// fn new(val: i32) -> Self { +// ListNode { +// next: None, +// val +// } +// } +// } + +impl Solution { + /// ソート済み連結リストから重複ノードをインプレースで削除する + /// + /// # Algorithm + /// `current` ポインタを先頭から走査し、 + /// `current.val == current.next.val` の間は `next` を `take()` でスキップ。 + /// 値が異なった時点で `current` を1つ進める(1ポインタ・インプレース)。 + /// + /// # Arguments + /// * `head` - 連結リストの所有権(空リストの場合は `None`) + /// + /// # Returns + /// 重複を除去したソート済み連結リストの所有権 + /// + /// # Complexity + /// - Time: O(n) — 各ノードを最大1回走査 + /// - Space: O(1) — スタック変数のみ、追加ヒープ確保なし + pub fn delete_duplicates(head: Option>) -> Option> { + // head の所有権を受け取り、変更後に返す + let mut head = head; + + // ── ガード節 ──────────────────────────────────────────────────── + // 空リスト or ノード1つ → 重複なし、所有権をそのまま返す + if head.is_none() || head.as_ref().unwrap().next.is_none() { + return head; + } + + // ── 1ポインタ走査(インプレース) ───────────────────────────── + // + // current: Option<&mut Box> + // - as_mut() で head の &mut 参照を取得 + // - ループ内で node.next.as_mut() により1つずつ前進 + // + // 【所有権の流れ】 + // head(所有) ──as_mut()──> current(&mut) + // current は head を所有したまま参照だけを持ち歩く + // + let mut current = head.as_mut(); + + while let Some(node) = current { + // ┌──────────────────────────────────────────────────────┐ + // │ 内側ループ: 同じ値が連続する限り next をスキップ │ + // │ │ + // │ [1] → [1] → [2] │ + // │ ↑ ↑ │ + // │ node next (take で所有権を取り出しドロップ) │ + // │ │ + // │ take() の動作: │ + // │ node.next の所有権を `skipped` へ移動 │ + // │ node.next は None になる │ + // │ skipped.next を node.next へ接続 │ + // │ skipped は スコープを抜けて自動 drop │ + // └──────────────────────────────────────────────────────┘ + while node.next.as_ref().map_or(false, |nxt| nxt.val == node.val) { + // next の所有権を取り出す(node.next は一時的に None) + let skipped = node.next.take().unwrap(); // Box + // スキップされたノードの next を現在ノードの next へ接続 + node.next = skipped.next; + // skipped はここで drop → ヒープ解放 + } + + // 値が異なる → current を1つ前進 + current = node.next.as_mut(); + } + + head // 変更済みリストの所有権を返す + } +} +``` + +--- + +## 5. 所有権フローの可視化 + +``` +【入力】 head = Some([1] → [1] → [2] → [3] → [3] → None) + +┌─ head (所有) ─────────────────────────────────────────────┐ +│ as_mut() で &mut を取り出し current へ │ +└────────────────────────────────────────────────────────────┘ + +Step 1 node.val(1) == next.val(1) → take() でスキップ + before: [1] → [1] → [2] → [3] → [3] → None + take(): skipped = Box([1] → [2] → ...) + after: [1] ──────→ [2] → [3] → [3] → None + drop: skipped (旧2番目ノード) を即時解放 ✅ + +Step 2 node.val(1) != next.val(2) → current を前進 + current → [2] + +Step 3 node.val(2) != next.val(3) → current を前進 + current → [3] + +Step 4 node.val(3) == next.val(3) → take() でスキップ + before: [3] → [3] → None + take(): skipped = Box([3] → None) + after: [3] → None + drop: skipped を即時解放 ✅ + +Step 5 node.next is None → while let を抜ける + +【出力】 Some([1] → [2] → [3] → None) ✅ +``` + +--- + +## 6. 計算量サマリー + +| 指標 | 値 | 説明 | +| ------------------ | ----------- | ---------------------------------- | +| **時間計算量** | `O(n)` | 各ノードを最大1回走査 | +| **空間計算量** | `O(1)` | スタック変数 `current` のみ | +| **ヒープ確保** | `0` 回 | 既存ノードの `next` 付け替えのみ | +| **安全性** | `safe Rust` | `unsafe` ブロックなし | +| **重複ノード解放** | 即時 | `take()` スコープ末尾で自動 `drop` | +| **clippy 適合** | ✅ | `#![deny(clippy::all)]` 相当 | diff --git a/Algorithm/Other/leetcode/83. Remove Duplicates from Sorted List/Claude 4.6 extended/Remove_Duplicates_from_Sorted_List_Typescript.md b/Algorithm/Other/leetcode/83. Remove Duplicates from Sorted List/Claude 4.6 extended/Remove_Duplicates_from_Sorted_List_Typescript.md new file mode 100644 index 00000000..e335bdd7 --- /dev/null +++ b/Algorithm/Other/leetcode/83. Remove Duplicates from Sorted List/Claude 4.6 extended/Remove_Duplicates_from_Sorted_List_Typescript.md @@ -0,0 +1,163 @@ +# LeetCode #83 - Remove Duplicates from Sorted List + +--- + +## 1. 問題の分析 + +### 競技プログラミング視点での分析 + +- ソート済みリストなので、**重複は必ず隣接**する → 1パスで解決可能 +- ポインタ操作のみ → 追加メモリ不要 `O(1)` space +- `n ≤ 300` と小さいため、計算量よりも**ポインタの正確な操作**が肝 + +### 業務開発視点での分析 + +- `ListNode | null` の Union型を正確に扱う null安全性が重要 +- 破壊的操作(`next`の付け替え)のため、**副作用を局所化**した明確な実装が必要 +- 型ガードで `current.next` の null チェックを明示 + +### TypeScript特有の考慮点 + +- `ListNode | null` → `!= null` での絞り込みで型ガード +- `while` ループ内での型推論を活用し、余分なキャストを排除 +- `readonly` は付けられない(破壊的操作必須)のでその代わりに関数スコープで副作用を限定 + +--- + +## 2. アルゴリズムアプローチ比較 + +| アプローチ | 時間計算量 | 空間計算量 | TS実装コスト | 型安全性 | 可読性 | 備考 | +| ------------------------- | ---------- | ---------- | ------------ | -------- | ------ | ---------------------------- | +| **インプレース1ポインタ** | O(n) | O(1) | 低 | 高 | 高 | ✅ 最適解 | +| 再帰 | O(n) | O(n) | 低 | 高 | 高 | スタックオーバーフローリスク | +| 配列変換+再構築 | O(n) | O(n) | 中 | 高 | 中 | 不要なメモリ確保 | + +--- + +## 3. 選択したアルゴリズムと理由 + +- **選択**: インプレース1ポインタ走査 +- **理由**: + - ソート済みリストの特性(隣接する重複)を最大限に活かし、1パスで完結 + - `O(1)` 追加メモリ、`O(n)` 時間の最適バランス + - 再帰は `n≤300` では問題ないが、スタック消費の観点で反復が優位 +- **TypeScript最適化ポイント**: + - `current` の型が `while` の条件式で `ListNode` に自動的に絞り込まれる型推論を活用 + - `current.next !== null` チェック後、型が自動的に `ListNode` へ narrowing + +--- + +## 4. 実装コード + +```typescript +// Runtime 0 ms +// Beats 100.00% +// Memory 58.86 MB +// Beats 26.83% +/** + * Definition for singly-linked list. + * class ListNode { + * val: number + * next: ListNode | null + * constructor(val?: number, next?: ListNode | null) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + * } + */ + +/** + * ソート済み連結リストから重複ノードを削除する + * + * アルゴリズム: + * current ポインタを先頭から走査し、 + * current.val === current.next.val の間は next を読み飛ばす。 + * 値が異なった時点で current を進める(1ポインタ・インプレース) + * + * @param head - 連結リストの先頭ノード (null の場合は空リスト) + * @returns 重複を除去したソート済み連結リストの先頭ノード + * @complexity Time: O(n), Space: O(1) + */ +function deleteDuplicates(head: ListNode | null): ListNode | null { + // ── 入力ガード ────────────────────────────────────────── + // 空リスト or ノードが1つ → 重複なし、そのまま返す + if (head === null || head.next === null) { + return head; + } + + // ── 1ポインタ走査(インプレース) ──────────────────────── + // TypeScriptの型narrowing: + // while条件で current != null が保証されるため + // ループ内で current は ListNode 型として扱われる + let current: ListNode = head; + + while (current.next !== null) { + // current.next は null でないことが確定(型: ListNode) + if (current.val === current.next.val) { + // ┌─────────────────────────────────────────┐ + // │ 重複検出: current.next をスキップ │ + // │ │ + // │ [1] → [1] → [2] │ + // │ ↑ ↑ │ + // │ current next(スキップ) │ + // │ │ + // │ [1] ──────→ [2] ← next.next を接続 │ + // └─────────────────────────────────────────┘ + current.next = current.next.next; + // current は進めない(次も重複の可能性があるため) + } else { + // 値が異なる → current を1つ進める + current = current.next; + } + } + + return head; +} +``` + +--- + +## ポインタ操作の可視化 + +``` +【初期状態】 head = [1, 1, 2, 3, 3] + +Step 1: current.val(1) === current.next.val(1) → next をスキップ + [1] → [1] → [2] → [3] → [3] → null + ↑ + current + ↓ current.next = current.next.next + [1] ──────→ [2] → [3] → [3] → null + ↑ + current + +Step 2: current.val(1) !== current.next.val(2) → current を進める + [1] → [2] → [3] → [3] → null + ↑ + current + +Step 3: current.val(2) !== current.next.val(3) → current を進める + [1] → [2] → [3] → [3] → null + ↑ + current + +Step 4: current.val(3) === current.next.val(3) → next をスキップ + [1] → [2] → [3] → null + ↑ + current + +Step 5: current.next === null → ループ終了 + +【出力】 [1, 2, 3] ✅ +``` + +--- + +## 計算量サマリー + +| 指標 | 値 | 説明 | +| -------------- | ------ | ----------------------------------- | +| **時間計算量** | `O(n)` | 各ノードを最大1回走査 | +| **空間計算量** | `O(1)` | ポインタ変数1つのみ、追加メモリなし | +| **安定性** | ✅ | 元の順序・値を保持 | +| **破壊的操作** | ✅ | 元リストをインプレースで変更 | diff --git a/Algorithm/Other/leetcode/90. Subsets II/Claude/README.html b/Algorithm/Other/leetcode/90. Subsets II/Claude/README.html index d957198f..310271a9 100644 --- a/Algorithm/Other/leetcode/90. Subsets II/Claude/README.html +++ b/Algorithm/Other/leetcode/90. Subsets II/Claude/README.html @@ -2563,6 +2563,16 @@

正当性の検証観点

+ diff --git a/Algorithm/Sliding Window Method/leetcode/3. Longest Substring Without Repeating Characters/Claude/README.html b/Algorithm/Sliding Window Method/leetcode/3. Longest Substring Without Repeating Characters/Claude/README.html index f0eed424..c6df64cf 100644 --- a/Algorithm/Sliding Window Method/leetcode/3. Longest Substring Without Repeating Characters/Claude/README.html +++ b/Algorithm/Sliding Window Method/leetcode/3. Longest Substring Without Repeating Characters/Claude/README.html @@ -1272,6 +1272,16 @@

+ diff --git a/Algorithm/TwoPointers/leetcode/67. Add Binary/Claude/README_react.html b/Algorithm/TwoPointers/leetcode/67. Add Binary/Claude/README_react.html index 8f1b80a6..685587e8 100644 --- a/Algorithm/TwoPointers/leetcode/67. Add Binary/Claude/README_react.html +++ b/Algorithm/TwoPointers/leetcode/67. Add Binary/Claude/README_react.html @@ -762,6 +762,17 @@

⚠️ 注意点

+ + diff --git a/Concurrency/1114. Print in Order/Claude Sonnet 4.5/README_react.html b/Concurrency/1114. Print in Order/Claude Sonnet 4.5/README_react.html index ce5467f3..79eadb57 100644 --- a/Concurrency/1114. Print in Order/Claude Sonnet 4.5/README_react.html +++ b/Concurrency/1114. Print in Order/Claude Sonnet 4.5/README_react.html @@ -1207,6 +1207,17 @@

ReactDOM.createRoot(document.getElementById('step-root')).render(); + + diff --git a/Concurrency/1115. Print FooBar Alternately/Claude Sonnet 4.5/README_react.html b/Concurrency/1115. Print FooBar Alternately/Claude Sonnet 4.5/README_react.html index dd95d1f7..46ff47cf 100644 --- a/Concurrency/1115. Print FooBar Alternately/Claude Sonnet 4.5/README_react.html +++ b/Concurrency/1115. Print FooBar Alternately/Claude Sonnet 4.5/README_react.html @@ -12,6 +12,17 @@ href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" rel="stylesheet" /> + + diff --git a/Concurrency/1116. Print Zero Even Odd/Claude Sonnet 4.5/README_react.html b/Concurrency/1116. Print Zero Even Odd/Claude Sonnet 4.5/README_react.html index 5014926a..039a2786 100644 --- a/Concurrency/1116. Print Zero Even Odd/Claude Sonnet 4.5/README_react.html +++ b/Concurrency/1116. Print Zero Even Odd/Claude Sonnet 4.5/README_react.html @@ -1597,6 +1597,17 @@

); + + diff --git a/Concurrency/1117. Building H2O/Claude Sonnet 4.5/README_react.html b/Concurrency/1117. Building H2O/Claude Sonnet 4.5/README_react.html index 10c70fff..9975bff3 100644 --- a/Concurrency/1117. Building H2O/Claude Sonnet 4.5/README_react.html +++ b/Concurrency/1117. Building H2O/Claude Sonnet 4.5/README_react.html @@ -828,6 +828,17 @@

最適化の比較

+ + diff --git a/Concurrency/1195. Fizz Buzz Multithreaded/Claude Sonnet 4.5/README_react.html b/Concurrency/1195. Fizz Buzz Multithreaded/Claude Sonnet 4.5/README_react.html index 6e39af35..c7fca37e 100644 --- a/Concurrency/1195. Fizz Buzz Multithreaded/Claude Sonnet 4.5/README_react.html +++ b/Concurrency/1195. Fizz Buzz Multithreaded/Claude Sonnet 4.5/README_react.html @@ -1568,6 +1568,17 @@

ReactDOM.render(, document.getElementById('react-root')); + + diff --git a/Concurrency/1226. The Dining Philosophers/Claude Sonnet 4.5/README_react.html b/Concurrency/1226. The Dining Philosophers/Claude Sonnet 4.5/README_react.html index 425c445f..b203cb2c 100644 --- a/Concurrency/1226. The Dining Philosophers/Claude Sonnet 4.5/README_react.html +++ b/Concurrency/1226. The Dining Philosophers/Claude Sonnet 4.5/README_react.html @@ -1034,6 +1034,17 @@

代替手法との比 + + diff --git a/DataStructures/LinkedLists/leetcode/2. Add Two Numbers/Claude/README.html b/DataStructures/LinkedLists/leetcode/2. Add Two Numbers/Claude/README.html index d89cd2ba..097a8273 100644 --- a/DataStructures/LinkedLists/leetcode/2. Add Two Numbers/Claude/README.html +++ b/DataStructures/LinkedLists/leetcode/2. Add Two Numbers/Claude/README.html @@ -144,6 +144,14 @@ } } + diff --git a/DataStructures/LinkedLists/leetcode/86. Partition List/Claude/README.html b/DataStructures/LinkedLists/leetcode/86. Partition List/Claude/README.html index 44a05c5b..99004eeb 100644 --- a/DataStructures/LinkedLists/leetcode/86. Partition List/Claude/README.html +++ b/DataStructures/LinkedLists/leetcode/86. Partition List/Claude/README.html @@ -133,6 +133,14 @@ font-weight: 500; } + diff --git a/DataStructures/LinkedLists/other/DoublyLinkedList/GPT/README.html b/DataStructures/LinkedLists/other/DoublyLinkedList/GPT/README.html index 19ff49f3..dee6d0d8 100644 --- a/DataStructures/LinkedLists/other/DoublyLinkedList/GPT/README.html +++ b/DataStructures/LinkedLists/other/DoublyLinkedList/GPT/README.html @@ -361,6 +361,14 @@ } } +
@@ -860,7 +868,7 @@

完全な処理フロー

setTimeout(() => { const newNode = animationController.createNode('15'); - container.insertBefore(newNode, nodes[1]); + container.insertBefore(newNode, container.children[1]); status.textContent = 'erase_at(2)を実行すると...'; }, 4000); } diff --git a/DataStructures/Map/leetcode/claude/README_react.html b/DataStructures/Map/leetcode/claude/README_react.html index 2ff98fba..9c0b0966 100644 --- a/DataStructures/Map/leetcode/claude/README_react.html +++ b/DataStructures/Map/leetcode/claude/README_react.html @@ -833,6 +833,17 @@

Two Sum

+ + diff --git a/DataStructures/Stacks/leetcode/85. Maximal Rectangle/GPT/README.html b/DataStructures/Stacks/leetcode/85. Maximal Rectangle/GPT/README.html index b45e6c71..4220d490 100644 --- a/DataStructures/Stacks/leetcode/85. Maximal Rectangle/GPT/README.html +++ b/DataStructures/Stacks/leetcode/85. Maximal Rectangle/GPT/README.html @@ -1057,6 +1057,17 @@

+ + diff --git "a/DataStructures/Trees/BFS\343\203\273DFS/leetcode/77. Combinations/Claude/README.html" "b/DataStructures/Trees/BFS\343\203\273DFS/leetcode/77. Combinations/Claude/README.html" index adba93c1..c2bfe607 100644 --- "a/DataStructures/Trees/BFS\343\203\273DFS/leetcode/77. Combinations/Claude/README.html" +++ "b/DataStructures/Trees/BFS\343\203\273DFS/leetcode/77. Combinations/Claude/README.html" @@ -1122,6 +1122,16 @@

アルゴリズムフローチャート

+ diff --git "a/DataStructures/Trees/BFS\343\203\273DFS/leetcode/87. Scramble String/Claude/README.html" "b/DataStructures/Trees/BFS\343\203\273DFS/leetcode/87. Scramble String/Claude/README.html" index a2ab8a65..3a84c464 100644 --- "a/DataStructures/Trees/BFS\343\203\273DFS/leetcode/87. Scramble String/Claude/README.html" +++ "b/DataStructures/Trees/BFS\343\203\273DFS/leetcode/87. Scramble String/Claude/README.html" @@ -23,6 +23,16 @@ href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.css" rel="stylesheet" /> + diff --git "a/DataStructures/Trees/BFS\343\203\273DFS/leetcode/87. Scramble String/GPT/README.html" "b/DataStructures/Trees/BFS\343\203\273DFS/leetcode/87. Scramble String/GPT/README.html" index 5de5c9c7..ecacf67e 100644 --- "a/DataStructures/Trees/BFS\343\203\273DFS/leetcode/87. Scramble String/GPT/README.html" +++ "b/DataStructures/Trees/BFS\343\203\273DFS/leetcode/87. Scramble String/GPT/README.html" @@ -1598,6 +1598,16 @@

計算量

+ diff --git a/DataStructures/bit manipulations/leetcode/89. Gray Code/Claude/README.html b/DataStructures/bit manipulations/leetcode/89. Gray Code/Claude/README.html index e9ac6f67..3db48fc7 100644 --- a/DataStructures/bit manipulations/leetcode/89. Gray Code/Claude/README.html +++ b/DataStructures/bit manipulations/leetcode/89. Gray Code/Claude/README.html @@ -1471,6 +1471,17 @@

アルゴリズム比較 + + diff --git a/DataStructures/bit manipulations/leetcode/89. Gray Code/GPT/README.html b/DataStructures/bit manipulations/leetcode/89. Gray Code/GPT/README.html index 06f59463..435485cc 100644 --- a/DataStructures/bit manipulations/leetcode/89. Gray Code/GPT/README.html +++ b/DataStructures/bit manipulations/leetcode/89. Gray Code/GPT/README.html @@ -140,6 +140,14 @@ } } + diff --git a/JavaScript/2618. Check if Object Instance of Class/Claude Code Sonnet 4.5/README_react.html b/JavaScript/2618. Check if Object Instance of Class/Claude Code Sonnet 4.5/README_react.html index 956df770..99bf3f8e 100644 --- a/JavaScript/2618. Check if Object Instance of Class/Claude Code Sonnet 4.5/README_react.html +++ b/JavaScript/2618. Check if Object Instance of Class/Claude Code Sonnet 4.5/README_react.html @@ -1841,6 +1841,16 @@

+ diff --git a/JavaScript/2619. Array Prototype Last/Claude Code Sonnet 4.5/README_react.html b/JavaScript/2619. Array Prototype Last/Claude Code Sonnet 4.5/README_react.html index c28b6427..1f5cfb38 100644 --- a/JavaScript/2619. Array Prototype Last/Claude Code Sonnet 4.5/README_react.html +++ b/JavaScript/2619. Array Prototype Last/Claude Code Sonnet 4.5/README_react.html @@ -628,6 +628,16 @@

最適化ポイント

+ diff --git a/JavaScript/2621. Sleep/Claude Code Sonnet 4.5/README_react.html b/JavaScript/2621. Sleep/Claude Code Sonnet 4.5/README_react.html index 8d25991b..dcafacb4 100644 --- a/JavaScript/2621. Sleep/Claude Code Sonnet 4.5/README_react.html +++ b/JavaScript/2621. Sleep/Claude Code Sonnet 4.5/README_react.html @@ -503,6 +503,16 @@

実装手法の比較

+ diff --git a/JavaScript/2622. Cache With Time Limit/Claude Code Sonnet 4.5/README_react.html b/JavaScript/2622. Cache With Time Limit/Claude Code Sonnet 4.5/README_react.html index 7d8b8ddd..d1c2a3c3 100644 --- a/JavaScript/2622. Cache With Time Limit/Claude Code Sonnet 4.5/README_react.html +++ b/JavaScript/2622. Cache With Time Limit/Claude Code Sonnet 4.5/README_react.html @@ -962,6 +962,16 @@

最適化のポイント

+ diff --git a/JavaScript/2626. Array Reduce Transformation/Claude Code Sonnet 4.5 extended/README_react.html b/JavaScript/2626. Array Reduce Transformation/Claude Code Sonnet 4.5 extended/README_react.html index 4e41d39d..c5c85c21 100644 --- a/JavaScript/2626. Array Reduce Transformation/Claude Code Sonnet 4.5 extended/README_react.html +++ b/JavaScript/2626. Array Reduce Transformation/Claude Code Sonnet 4.5 extended/README_react.html @@ -97,6 +97,14 @@ box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3); } +
diff --git a/JavaScript/2627. Debounce/Claude Code Sonnet 4.5 extended/README.md b/JavaScript/2627. Debounce/Claude Code Sonnet 4.5 extended/README.md index fad92015..8424a598 100644 --- a/JavaScript/2627. Debounce/Claude Code Sonnet 4.5 extended/README.md +++ b/JavaScript/2627. Debounce/Claude Code Sonnet 4.5 extended/README.md @@ -143,8 +143,7 @@ graph LR ```python from __future__ import annotations from typing import Callable, Any -from threading import Timer - +from threading import Timer, Lock def debounce(fn: Callable[..., Any], t: float) -> Callable[..., None]: """ @@ -171,18 +170,23 @@ def debounce(fn: Callable[..., Any], t: float) -> Callable[..., None]: """ # タイマーオブジェクトを保持するクロージャ変数 timer: Timer | None = None + lock = Lock() def debounced_func(*args: Any, **kwargs: Any) -> None: nonlocal timer - # 既存のタイマーがあればキャンセル - if timer is not None: - timer.cancel() + with lock: + # 既存のタイマーがあればキャンセル + if timer is not None: + timer.cancel() - # 新しいタイマーをセット(t/1000 秒後に fn を実行) - # threading.Timer は秒単位なので、ミリ秒を秒に変換 - timer = Timer(t / 1000.0, fn, args=args, kwargs=kwargs) - timer.start() + # 新しいタイマーをセット(t/1000 秒後に fn を実行) + # threading.Timer は秒単位なので、ミリ秒を秒に変換 + local_timer = Timer(t / 1000.0, fn, args=args, kwargs=kwargs) + timer = local_timer + + # ロック外でタイマーを開始して、ロックの保持時間を最小化する + local_timer.start() return debounced_func @@ -205,18 +209,21 @@ class Solution: デバウンスされた関数 """ timer: Timer | None = None + lock = Lock() def debounced(*args: Any, **kwargs: Any) -> None: nonlocal timer - - # 基底条件: タイマーが存在すればキャンセル - if timer is not None: - timer.cancel() - - # 遷移: 新しいタイマーを作成して開始 - # t ミリ秒 = t/1000 秒 - timer = Timer(t / 1000.0, fn, args=args, kwargs=kwargs) - timer.start() + with lock: + # 基底条件: タイマーが存在すればキャンセル + if timer is not None: + timer.cancel() + + # 遷移: 新しいタイマーを作成して開始 + # t ミリ秒 = t/1000 秒 + local_timer = Timer(t / 1000.0, fn, args=args, kwargs=kwargs) + timer = local_timer + + local_timer.start() return debounced @@ -275,6 +282,7 @@ if __name__ == "__main__": ```python # asyncio版(参考) import asyncio +import inspect from typing import Callable, Coroutine, Any def debounce_async(fn: Callable, t: float) -> Callable[..., Coroutine[Any, Any, None]]: @@ -290,7 +298,9 @@ def debounce_async(fn: Callable, t: float) -> Callable[..., Coroutine[Any, Any, async def delayed(): await asyncio.sleep(t / 1000.0) - fn(*args, **kwargs) + result = fn(*args, **kwargs) + if inspect.isawaitable(result): + await result task = asyncio.create_task(delayed()) @@ -318,17 +328,23 @@ if timer is not None: **クラスベース**: ```python +from threading import Timer, Lock + class Debouncer: def __init__(self, fn: Callable, t: float): self.fn = fn self.t = t self.timer: Timer | None = None + self.lock = Lock() def __call__(self, *args, **kwargs): - if self.timer: - self.timer.cancel() - self.timer = Timer(self.t / 1000.0, self.fn, args, kwargs) - self.timer.start() + with self.lock: + if self.timer: + self.timer.cancel() + local_timer = Timer(self.t / 1000.0, self.fn, args, kwargs) + self.timer = local_timer + + local_timer.start() ``` ### 4. GIL(Global Interpreter Lock)の影響 @@ -388,7 +404,7 @@ t1.start() t2.start() ``` -**注意**: `threading.Timer` 自体はスレッドセーフだが、`nonlocal timer` への同時アクセスは保護されていない。本格的なマルチスレッド環境では `Lock` が必要。 +**注意**: 本実装は `threading.Lock` を使用して `timer` の管理(タイマーの生成と `timer.cancel()` の呼び出し)のみを保護しており、ラップされた関数 `fn` 自体のスレッドセーフ性や、`t = 0` の場合のレースコンディションを保証するものではありません。 ### 6. メモリリーク防止 @@ -470,14 +486,25 @@ my_func_debounced = debounce(my_func, 100) - **throttle**: 最初の呼び出しを即座に実行し、以降 `t` ミリ秒間は無視 ```python +import time +from threading import Lock + # throttle の例(参考) def throttle(fn: Callable, t: float) -> Callable: - last_call = [0.0] + last_call: float = 0.0 + lock = Lock() def throttled(*args, **kwargs): - now = time.time() - if now - last_call[0] >= t / 1000.0: - last_call[0] = now + nonlocal last_call + now = time.monotonic() + should_call = False + + with lock: + if now - last_call >= t / 1000.0: + last_call = now + should_call = True + + if should_call: fn(*args, **kwargs) return throttled diff --git a/JavaScript/2629. Function Composition/Claude Code Sonnet 4.6 extended/README_react.html b/JavaScript/2629. Function Composition/Claude Code Sonnet 4.6 extended/README_react.html index 6ffd1e06..ee0d8dca 100644 --- a/JavaScript/2629. Function Composition/Claude Code Sonnet 4.6 extended/README_react.html +++ b/JavaScript/2629. Function Composition/Claude Code Sonnet 4.6 extended/README_react.html @@ -51,6 +51,16 @@ integrity="sha384-6QJu8apxMmB9TiPVWzYKF5pRgKcz7snO0/QU+MrWmgBLECQjoa6erxX2VQ5t41Jd" crossorigin="anonymous" > + + diff --git a/Mathematics/Finite State Machine/leetcode/65. Valid Number/Claude/README.html b/Mathematics/Finite State Machine/leetcode/65. Valid Number/Claude/README.html index fe354265..da5f3d41 100644 --- a/Mathematics/Finite State Machine/leetcode/65. Valid Number/Claude/README.html +++ b/Mathematics/Finite State Machine/leetcode/65. Valid Number/Claude/README.html @@ -26,6 +26,9 @@ + diff --git a/Mathematics/Fundamentals/HackerRank/Claude/Easy/Halloween party/Halloween_party.html b/Mathematics/Fundamentals/HackerRank/Claude/Easy/Halloween party/Halloween_party.html index 3cd6bf26..2d58152a 100644 --- a/Mathematics/Fundamentals/HackerRank/Claude/Easy/Halloween party/Halloween_party.html +++ b/Mathematics/Fundamentals/HackerRank/Claude/Easy/Halloween party/Halloween_party.html @@ -43,6 +43,7 @@ + + + + + + - - - - + + + + + + - - - - - - - + + + + + + + 📝 可読性の向上

- - - + + + - - + + + - - - - + + + + + + - - - - - + + + + + diff --git a/public/Algorithm/BinarySearch/leetcode/98. Validate Binary Search Tree/Claude Sonnet 4.5/README_react.html b/public/Algorithm/BinarySearch/leetcode/98. Validate Binary Search Tree/Claude Sonnet 4.5/README_react.html index f6d45838..a13cac56 100644 --- a/public/Algorithm/BinarySearch/leetcode/98. Validate Binary Search Tree/Claude Sonnet 4.5/README_react.html +++ b/public/Algorithm/BinarySearch/leetcode/98. Validate Binary Search Tree/Claude Sonnet 4.5/README_react.html @@ -913,11 +913,21 @@

代替手法との比 - - - - - + + + + + + - - - - + + + + + + - - + + + - - - - + + + + + + - - - - + + + + + - - - - - - - + + + + + + + - - - + + + - + + - - - - + + + + + + - - - - + + + + + + - - - - + + + + + - - + + + - - + + + - - + + + + - - + + + - - - - - + + + + + + - - + + + - - + + + - - + + + 代替手法との比 - - - - - + + + + + + - - - - + + + + + + + - - + + + - - + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+

+ アルゴリズム概要 +

+ +
+
+
O(n)
+
時間計算量
+
+
+
O(1)
+
空間計算量
+
+
+
+ 0 〜 300 +
+
ノード数制約
+
+
+
+ -100〜100 +
+
値の範囲
+
+
+ +
+

問題の要点

+

+ ソート済み単方向連結リストの先頭ノード + head + を受け取り、 各要素がちょうど 1 回だけ現れるようにリストを変更して返す。
+ ソート済みであるという特性から、重複は必ず隣接して現れる。 これにより 1 + パスの線形走査で解決できる。 +

+
+ +
+
+
入力例 1
+
head = [1, 1, 2]
+
出力: [1, 2]
+
+
+
入力例 2
+
head = [1, 1, 2, 3, 3]
+
出力: [1, 2, 3]
+
+
+ +
+
⚠️ 落とし穴
+
    +
  • + 🔸 重複スキップ後に + current + を進めてはいけない(3連続重複を見逃す) +
  • +
  • + 🔸 head is None と + head.next is None + の両方をガード +
  • +
  • 🔸 新しいノードを作成しない — インプレースでポインタだけ付け替える
  • +
+
+
+ + +
+

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

+
+
+ + +
+

+ 実装コード +

+
+
+ + +
+

+ 処理フローチャート +

+ + +
+
+ 開始 / 終了 +
+
+ 処理ノード +
+
+ 条件分岐 +
+
+ はい / 正常終了 +
+
+ 重複検出 +
+
+ ループバック +
+
+ +
+
+ flowchart TD + Start([" 開始 "]) + Guard["ガード節
head is None OR head.next is None ?"] + GuardTrue["return head
変更なしで即時返却"] + Init["初期化
current = head"] + LoopCheck{"current.next
is not None ?"} + Cache["nxt = current.next
次ノードをキャッシュ"] + DupCheck{"current.val
== nxt.val ?"} + Skip["nxt をスキップ
current.next = nxt.next
※ current は動かさない"] + Advance["current を前進
current = nxt"] + Return["return head
重複除去済みリストを返す"] + End([" 終了 "]) + + Start --> Guard + Guard -- "True
空 or 単一ノード" --> GuardTrue + Guard -- "False
複数ノード存在" --> Init + GuardTrue --> End + Init --> LoopCheck + LoopCheck -- "False
current.next が None
ループ終了" --> Return + LoopCheck -- "True
次ノード存在" --> Cache + Cache --> DupCheck + DupCheck -- "True
重複あり" --> Skip + DupCheck -- "False
重複なし" --> Advance + Skip -- "再チェック
同じ current で
ループ先頭へ戻る" --> LoopCheck + Advance -- "次ノードへ
ループ先頭へ戻る" --> LoopCheck + Return --> End + + style Start fill:#d1fae5,stroke:#10b981,stroke-width:2px,color:#065f46 + style End fill:#d1fae5,stroke:#10b981,stroke-width:2px,color:#065f46 + style Guard fill:#e0f2fe,stroke:#0284c7,stroke-width:2px,color:#0c4a6e + style GuardTrue fill:#d1fae5,stroke:#059669,stroke-width:2px,color:#065f46 + style Init fill:#e0f2fe,stroke:#0284c7,stroke-width:2px,color:#0c4a6e + style LoopCheck fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#92400e + style Cache fill:#f1f5f9,stroke:#64748b,stroke-width:2px,color:#1e293b + style DupCheck fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#92400e + style Skip fill:#fee2e2,stroke:#dc2626,stroke-width:2px,color:#991b1b + style Advance fill:#f1f5f9,stroke:#64748b,stroke-width:2px,color:#1e293b + style Return fill:#d1fae5,stroke:#059669,stroke-width:2.5px,color:#065f46 + + linkStyle 0 stroke:#64748b,stroke-width:2px + linkStyle 1 stroke:#059669,stroke-width:2px + linkStyle 2 stroke:#64748b,stroke-width:2px + linkStyle 3 stroke:#059669,stroke-width:2px + linkStyle 4 stroke:#64748b,stroke-width:2px + linkStyle 5 stroke:#059669,stroke-width:2px + linkStyle 6 stroke:#64748b,stroke-width:2px + linkStyle 7 stroke:#64748b,stroke-width:2px + linkStyle 8 stroke:#dc2626,stroke-width:2px + linkStyle 9 stroke:#64748b,stroke-width:2px + linkStyle 10 stroke:#a855f7,stroke-width:2px,stroke-dasharray:6 4 + linkStyle 11 stroke:#a855f7,stroke-width:2px,stroke-dasharray:6 4 + linkStyle 12 stroke:#059669,stroke-width:2px +
+
+ + +
+
+
+ ① ガード節(Guard) +
+

+ リストが空(None)、またはノードが1つ(head.next is None)なら重複は存在しない。head を返して終了(緑の矢印)。 +

+
+
+
+ ② ループ条件チェック +
+

+ current.next is None + になったらループ終了(緑矢印 → return)。
current.next + が存在する間は内部処理を継続(下方向)。 +

+
+
+
+ ③ 重複検出 → Skip(赤矢印) +
+

+ current.val == nxt.val なら + current.next = nxt.next で + nxt を切り離す。current は移動せず、ループ先頭へ戻って再チェック(紫の破線)。 +

+
+
+
+ ④ 値が異なる → Advance(紫破線) +
+

+ current.val != nxt.val なら + current = nxt + で1つ前進。ループ先頭へ戻って次のノードを比較(紫の破線)。 +

+
+
+
+ + +
+

+ 計算量分析 +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ 指標 + + 値 + + 理由 +
+ 時間計算量 + + O(n) + + 各ノードを最大 1 回走査。重複スキップ時も + current は移動しないが、next + の参照が前進するため全体では O(n) +
+ 空間計算量 + + O(1) + + スタック変数 current / + nxt のみ。新規ノード生成ゼロ +
+ ヒープ確保 + + 0 回 + + 既存ノードの + next + 付け替えのみ。新オブジェクト生成なし +
+
+ +
+

アプローチ比較

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ アプローチ + + Time + + Space + + 特徴 +
+ ✅ 1ポインタ・インプレース(本実装) + + O(n) + + O(1) + + 最適。ヒープ確保ゼロ +
+ 再帰 + + O(n) + + O(n) + + 可読性高いがコールスタック消費 +
+ 配列変換+再構築 + + O(n) + + O(n) + + 不要なオブジェクト生成多数 +
+
+
+
+ + + + + + + + diff --git a/public/Algorithm/Other/leetcode/90. Subsets II/Claude/README.html b/public/Algorithm/Other/leetcode/90. Subsets II/Claude/README.html index fff2f81a..629afcfd 100644 --- a/public/Algorithm/Other/leetcode/90. Subsets II/Claude/README.html +++ b/public/Algorithm/Other/leetcode/90. Subsets II/Claude/README.html @@ -2563,11 +2563,21 @@

正当性の検証観点

- - - - - + + + + + + - - - - + + + + + + - + + - - + + + - - - - + + + + + + + - + + - - + + + - - - - - + + + + + + + diff --git a/public/Concurrency/1115. Print FooBar Alternately/Claude Sonnet 4.5/README_react.html b/public/Concurrency/1115. Print FooBar Alternately/Claude Sonnet 4.5/README_react.html index 65ca689f..6ef6f0ca 100644 --- a/public/Concurrency/1115. Print FooBar Alternately/Claude Sonnet 4.5/README_react.html +++ b/public/Concurrency/1115. Print FooBar Alternately/Claude Sonnet 4.5/README_react.html @@ -9,22 +9,33 @@ - - - + + + + + - + - + ); - - - - - + + + + + + + diff --git a/public/Concurrency/1117. Building H2O/Claude Sonnet 4.5/README_react.html b/public/Concurrency/1117. Building H2O/Claude Sonnet 4.5/README_react.html index aeb3dce2..a6508b51 100644 --- a/public/Concurrency/1117. Building H2O/Claude Sonnet 4.5/README_react.html +++ b/public/Concurrency/1117. Building H2O/Claude Sonnet 4.5/README_react.html @@ -828,11 +828,22 @@

最適化の比較

- - - - - + + + + + + + - - - - - + + + + + + + diff --git a/public/Concurrency/1226. The Dining Philosophers/Claude Sonnet 4.5/README_react.html b/public/Concurrency/1226. The Dining Philosophers/Claude Sonnet 4.5/README_react.html index 5e041380..dfa0e70f 100644 --- a/public/Concurrency/1226. The Dining Philosophers/Claude Sonnet 4.5/README_react.html +++ b/public/Concurrency/1226. The Dining Philosophers/Claude Sonnet 4.5/README_react.html @@ -1034,11 +1034,22 @@

代替手法との比 - - - - - + + + + + + + - - - - + + + + + - - - - + + + + + - - - - + + + + + - - - - - + + + + + - - + + + +
@@ -860,7 +868,7 @@

完全な処理フロー

setTimeout(() => { const newNode = animationController.createNode('15'); - container.insertBefore(newNode, nodes[1]); + container.insertBefore(newNode, container.children[1]); status.textContent = 'erase_at(2)を実行すると...'; }, 4000); } diff --git a/public/DataStructures/LinkedLists/other/LinkedList/GPT/README.html b/public/DataStructures/LinkedLists/other/LinkedList/GPT/README.html index 2a712dc0..765adb99 100644 --- a/public/DataStructures/LinkedLists/other/LinkedList/GPT/README.html +++ b/public/DataStructures/LinkedLists/other/LinkedList/GPT/README.html @@ -5,7 +5,7 @@ Linked List Operations - Technical Analysis - - + + - - - - - + + + + + + + - + + - - + + + - - + + + - - - - - + + + + + - - - - - + + + + + - - - + + + + - - - - - - + + + + + + + + + - - + + + - - - - + + + + + + - - + + + - - + + + - - - - + + + + + + + + + + + - - + + + アルゴリズム比較 - - - - - + + + + + + + + - + - - - + + + + @@ -930,15 +938,15 @@

計算量

- + - + - - - + + + - - - - - + + + + + + diff --git a/public/JavaScript/2619. Array Prototype Last/Claude Code Sonnet 4.5/README_react.html b/public/JavaScript/2619. Array Prototype Last/Claude Code Sonnet 4.5/README_react.html index 730c65aa..fd7a80ef 100644 --- a/public/JavaScript/2619. Array Prototype Last/Claude Code Sonnet 4.5/README_react.html +++ b/public/JavaScript/2619. Array Prototype Last/Claude Code Sonnet 4.5/README_react.html @@ -10,7 +10,7 @@ rel="stylesheet" /> + + + + + - - - - - + + + + + - - - - - + + + + + + - - - - - + + + + + + - - - - + + + + - + - + diff --git a/public/JavaScript/2624. Snail Traversal/Claude Code Sonnet 4.5/README_react.html b/public/JavaScript/2624. Snail Traversal/Claude Code Sonnet 4.5/README_react.html index 9817b543..c0952c06 100644 --- a/public/JavaScript/2624. Snail Traversal/Claude Code Sonnet 4.5/README_react.html +++ b/public/JavaScript/2624. Snail Traversal/Claude Code Sonnet 4.5/README_react.html @@ -18,10 +18,8 @@ 実装方法の比較< - - - - - + + + + + diff --git a/public/JavaScript/2626. Array Reduce Transformation/Claude Code Sonnet 4.5 extended/README_react.html b/public/JavaScript/2626. Array Reduce Transformation/Claude Code Sonnet 4.5 extended/README_react.html index d9ba3b57..55b89830 100644 --- a/public/JavaScript/2626. Array Reduce Transformation/Claude Code Sonnet 4.5 extended/README_react.html +++ b/public/JavaScript/2626. Array Reduce Transformation/Claude Code Sonnet 4.5 extended/README_react.html @@ -20,9 +20,7 @@ +
@@ -870,29 +876,19 @@

最適化のポイント< diff --git a/public/JavaScript/2627. Debounce/Claude Code Sonnet 4.5 extended/README_react.html b/public/JavaScript/2627. Debounce/Claude Code Sonnet 4.5 extended/README_react.html index 5ae89ec5..72a1c045 100644 --- a/public/JavaScript/2627. Debounce/Claude Code Sonnet 4.5 extended/README_react.html +++ b/public/JavaScript/2627. Debounce/Claude Code Sonnet 4.5 extended/README_react.html @@ -18,7 +18,7 @@ 実装比較

diff --git a/public/JavaScript/2629. Function Composition/Claude Code Sonnet 4.6 extended/README_react.html b/public/JavaScript/2629. Function Composition/Claude Code Sonnet 4.6 extended/README_react.html index 89062071..ebbf0fc7 100644 --- a/public/JavaScript/2629. Function Composition/Claude Code Sonnet 4.6 extended/README_react.html +++ b/public/JavaScript/2629. Function Composition/Claude Code Sonnet 4.6 extended/README_react.html @@ -20,38 +20,36 @@ /> + + + + + + - - - - + + + + +