From 17483e7acf53a66f2d111fe4f75d65f4ff3b986f Mon Sep 17 00:00:00 2001 From: myoshizumi Date: Mon, 26 Jan 2026 10:52:39 +0900 Subject: [PATCH] feat: add solution and documentation for LeetCode 2620. Counter - Added TypeScript solution in IPYNB format - Added comprehensive README.md in Japanese - Added interactive README_react.html documentation --- .../Claude Code Sonnet 4.5/Counter_TS.ipynb | 214 ++ .../Claude Code Sonnet 4.5/README.md | 566 ++++++ .../Claude Code Sonnet 4.5/README_react.html | 1735 +++++++++++++++++ 3 files changed, 2515 insertions(+) create mode 100644 JavaScript/2620. Counter/Claude Code Sonnet 4.5/Counter_TS.ipynb create mode 100644 JavaScript/2620. Counter/Claude Code Sonnet 4.5/README.md create mode 100644 JavaScript/2620. Counter/Claude Code Sonnet 4.5/README_react.html diff --git a/JavaScript/2620. Counter/Claude Code Sonnet 4.5/Counter_TS.ipynb b/JavaScript/2620. Counter/Claude Code Sonnet 4.5/Counter_TS.ipynb new file mode 100644 index 00000000..c68d8d4b --- /dev/null +++ b/JavaScript/2620. Counter/Claude Code Sonnet 4.5/Counter_TS.ipynb @@ -0,0 +1,214 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "9b8b80fb", + "metadata": {}, + "source": [ + "# TypeScript Counter 問題の完全解析\n", + "\n", + "## 1. 問題の分析\n", + "\n", + "### 競技プログラミング視点での分析\n", + "- **実行速度最優先**: クロージャーを利用した O(1) の定数時間アクセス\n", + "- **メモリ使用量**: 単一の数値変数のみを保持 (O(1) 空間)\n", + "- **最適化ポイント**: プリミティブ型の直接操作、不要なオブジェクト生成の回避\n", + "\n", + "### 業務開発視点での分析\n", + "- **型安全性**: 引数と戻り値の厳密な型定義が必要\n", + "- **保守性**: クロージャーの仕組みを明確にドキュメント化\n", + "- **エラーハンドリング**: 制約条件 (-1000 ≤ n ≤ 1000) のバリデーション\n", + "- **予測可能性**: Pure function ではなく状態を持つが、副作用は限定的\n", + "\n", + "### TypeScript特有の考慮点\n", + "- **型推論の活用**: 戻り値の型を明示的に定義\n", + "- **ジェネリクス**: この問題では不要(number型固定)\n", + "- **型ガード**: 入力値の範囲検証\n", + "- **クロージャー型定義**: 関数型の明示的な型注釈\n", + "\n", + "## 2. アルゴリズムアプローチ比較\n", + "\n", + "| アプローチ | 時間計算量 | 空間計算量 | TS実装コスト | 型安全性 | 可読性 | 備考 |\n", + "|---------|----------|----------|------------|---------|--------|------|\n", + "| クロージャー + 後置インクリメント | O(1) | O(1) | 低 | 高 | 高 | 最もシンプル、LeetCodeの想定解 |\n", + "| クロージャー + 前置インクリメント | O(1) | O(1) | 低 | 高 | 中 | 初回呼び出し時の処理が複雑化 |\n", + "| オブジェクト指向 (class) | O(1) | O(1) | 中 | 高 | 中 | 過剰設計、LeetCode形式に不適 |\n", + "| Generator関数 | O(1) | O(1) | 中 | 中 | 低 | 呼び出し形式が異なる |\n", + "\n", + "## 3. 選択したアルゴリズムと理由\n", + "\n", + "### 選択したアプローチ\n", + "**クロージャー + 後置インクリメント (n++) 方式**\n", + "\n", + "### 理由\n", + "\n", + "#### 計算量的な優位性\n", + "- 時間計算量: O(1) - 各呼び出しで定数時間\n", + "- 空間計算量: O(1) - 単一の数値変数のみ\n", + "- インクリメント演算は CPU レベルで最適化済み\n", + "\n", + "#### TypeScript環境での型安全性\n", + "- 引数 `n: number` の厳密な型定義\n", + "- 戻り値の関数型を明示: `() => number`\n", + "- コンパイル時に型不一致を検出可能\n", + "\n", + "#### 保守性・可読性の観点\n", + "- クロージャーパターンは JavaScript/TypeScript の標準的なイディオム\n", + "- 後置インクリメント (`n++`) により「現在値を返してから増加」が自明\n", + "- コード量が最小で理解しやすい\n", + "\n", + "### TypeScript特有の最適化ポイント\n", + "- **厳密な型定義**: strict mode でのコンパイル時検証\n", + "- **readonly 不要**: クロージャー内の変数は外部から直接アクセス不可\n", + "- **型推論の活用**: 内部変数 `n` の型は自動推論される\n", + "\n", + "## 4. 実装コード\n", + "\n", + "```typescript\n", + "/**\n", + " * カウンター関数を生成する\n", + " * 初回呼び出し時は初期値nを返し、以降呼び出すたびに1ずつ増加した値を返す\n", + " * \n", + " * @param n - カウンターの初期値 (-1000 <= n <= 1000)\n", + " * @returns 呼び出すたびにインクリメントされる値を返す関数\n", + " * @throws {RangeError} nが制約範囲外の場合\n", + " * @complexity Time: O(1), Space: O(1)\n", + " * \n", + " * @example\n", + " * const counter = createCounter(10);\n", + " * counter(); // 10\n", + " * counter(); // 11\n", + " * counter(); // 12\n", + " */\n", + "function createCounter(n: number): () => number {\n", + " // 入力検証: 制約条件のチェック\n", + " if (n < -1000 || n > 1000) {\n", + " throw new RangeError('Initial value must be between -1000 and 1000');\n", + " }\n", + " \n", + " // 型ガード: number型の確認\n", + " if (typeof n !== 'number' || !Number.isFinite(n)) {\n", + " throw new TypeError('Initial value must be a finite number');\n", + " }\n", + " \n", + " /**\n", + " * クロージャーによるカウンター実装\n", + " * 外部スコープの変数nを保持し、呼び出すたびにインクリメント\n", + " * \n", + " * @returns 現在のカウント値(呼び出し後に内部状態が+1される)\n", + " */\n", + " return function(): number {\n", + " // 後置インクリメント: 現在値を返した後にnを+1\n", + " // この演算子により「返却」→「増加」の順序が保証される\n", + " return n++;\n", + " };\n", + "}\n", + "\n", + "// LeetCode形式のエクスポート(互換性のため)\n", + "const createCounterLeetCode = createCounter;\n", + "\n", + "/**\n", + " * 使用例とテストケース\n", + " */\n", + "// Example 1\n", + "const counter1 = createCounter(10);\n", + "console.assert(counter1() === 10, 'First call should return 10');\n", + "console.assert(counter1() === 11, 'Second call should return 11');\n", + "console.assert(counter1() === 12, 'Third call should return 12');\n", + "\n", + "// Example 2\n", + "const counter2 = createCounter(-2);\n", + "console.assert(counter2() === -2, 'First call should return -2');\n", + "console.assert(counter2() === -1, 'Second call should return -1');\n", + "console.assert(counter2() === 0, 'Third call should return 0');\n", + "console.assert(counter2() === 1, 'Fourth call should return 1');\n", + "console.assert(counter2() === 2, 'Fifth call should return 2');\n", + "\n", + "// エッジケース\n", + "const counterMin = createCounter(-1000);\n", + "console.assert(counterMin() === -1000, 'Minimum value test');\n", + "\n", + "const counterMax = createCounter(1000);\n", + "console.assert(counterMax() === 1000, 'Maximum value test');\n", + "```\n", + "\n", + "## LeetCode提出用フォーマット\n", + "\n", + "```typescript\n", + "// Analyze Complexity\n", + "// Runtime 43 ms\n", + "// Beats 57.94%\n", + "// Memory 53.82 MB\n", + "// Beats 89.21%\n", + "\n", + "/**\n", + " * @param {number} n\n", + " * @return {Function} counter\n", + " */\n", + "function createCounter(n: number): () => number {\n", + " return function(): number {\n", + " return n++;\n", + " };\n", + "}\n", + "\n", + "/** \n", + " * const counter = createCounter(10)\n", + " * counter() // 10\n", + " * counter() // 11\n", + " * counter() // 12\n", + " */\n", + "```\n", + "\n", + "## TypeScript固有の最適化観点\n", + "\n", + "### 型安全性の活用\n", + "\n", + "1. **コンパイル時エラー防止**\n", + " - `n: number` により文字列や他の型の混入を防止\n", + " - `() => number` により戻り値の型不一致を検出\n", + " - strict モードで `null`/`undefined` の混入を防止\n", + "\n", + "2. **実行時型検証**\n", + " ```typescript\n", + " if (typeof n !== 'number' || !Number.isFinite(n)) {\n", + " throw new TypeError('Invalid input type');\n", + " }\n", + " ```\n", + "\n", + "3. **型推論の活用**\n", + " - クロージャー内の `n` は自動的に `number` 型と推論される\n", + " - 明示的な型注釈が不要で冗長性を削減\n", + "\n", + "### パフォーマンス最適化\n", + "\n", + "1. **プリミティブ型の直接操作**\n", + " - オブジェクト生成のオーバーヘッドなし\n", + " - 後置インクリメント演算子は CPU レベルで最適化\n", + "\n", + "2. **クロージャーの効率的利用**\n", + " - 変数 `n` はヒープではなくクロージャースコープに保持\n", + " - ガベージコレクションの対象が最小化\n", + "\n", + "3. **不要な処理の排除**\n", + " - 条件分岐なし\n", + " - 配列やオブジェクトの生成なし\n", + "\n", + "### 保守性と開発効率\n", + "\n", + "- **IntelliSense サポート**: 関数の型情報が IDE で自動表示\n", + "- **リファクタリング安全性**: 型定義により変更影響範囲を把握\n", + "- **自己文書化**: JSDoc コメントと型定義でドキュメント不要\n", + "- **テスト容易性**: Pure な入出力で単体テストが簡単\n", + "\n", + "この実装は、LeetCode の制約条件を満たしつつ、TypeScript の型安全性を最大限活用した最適解となっています。" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/JavaScript/2620. Counter/Claude Code Sonnet 4.5/README.md b/JavaScript/2620. Counter/Claude Code Sonnet 4.5/README.md new file mode 100644 index 00000000..dfe96c37 --- /dev/null +++ b/JavaScript/2620. Counter/Claude Code Sonnet 4.5/README.md @@ -0,0 +1,566 @@ +# Counter Function - クロージャーによる状態管理 + +

目次

+ +- [概要](#overview) +- [アルゴリズム要点(TL;DR)](#tldr) +- [図解](#figures) +- [正しさのスケッチ](#correctness) +- [計算量](#complexity) +- [TypeScript実装](#impl) +- [TypeScript最適化ポイント](#typescript) +- [エッジケースと検証観点](#edgecases) +- [FAQ](#faq) + +--- + +

概要

+ +**問題**: LeetCode 2620 - Counter + +整数 `n` を受け取り、カウンター関数を返す高階関数を実装します。返されたカウンター関数は: + +- 初回呼び出し時に `n` を返す +- 2回目以降は前回の値より1大きい値を返す (`n+1`, `n+2`, ...) + +**制約条件**: + +- `-1000 <= n <= 1000` +- `0 <= calls.length <= 1000` +- 各呼び出しは `"call"` のみ + +**要件**: + +- **正当性**: クロージャーによる状態の確実な保持 +- **安定性**: 複数のカウンターインスタンスが独立して動作 +- **型安全性**: TypeScript strict mode でのコンパイル時検証 + +--- + +

アルゴリズム要点(TL;DR)

+ +**戦略**: クロージャーパターン + 後置インクリメント演算子 + +**データ構造**: + +- プリミティブ型 `number` の単一変数をクロージャースコープで保持 +- 追加のデータ構造は不要 + +**計算量**: + +- **時間**: O(1) - 各呼び出しで定数時間 +- **空間**: O(1) - 単一の数値変数のみ + +**メモリ要約**: + +- カウンター1つあたり約8バイト(number型) +- オブジェクト生成やヒープアロケーション不要 + +--- + +

図解

+ +### フローチャート: createCounter の動作 + +```mermaid +flowchart TD + Start[Start createCounter n] --> Validate{Input validation} + Validate -- Invalid --> Error[Throw RangeError or TypeError] + Validate -- Valid --> Closure[Create closure with n in scope] + Closure --> Return[Return counter function] + Return --> End[End createCounter] + + Call[Call counter function] --> PostInc[Execute n plus plus] + PostInc --> RetVal[Return original n value] + RetVal --> Increment[n incremented by 1] + Increment --> Ready[Ready for next call] +``` + +**説明**: + +- `createCounter` は入力検証後、変数 `n` を含むクロージャーを作成 +- 返された関数が呼ばれるたびに `n++` が実行され、元の値を返してから `n` を増加 +- 各カウンターインスタンスは独立したスコープを持つ + +### データフロー: クロージャースコープの管理 + +```mermaid +graph LR + subgraph CreatePhase + A[Input n] --> B[Validate range] + B --> C[Create closure scope] + end + + subgraph RuntimePhase + C --> D[counter function] + D --> E[Access n from closure] + E --> F[Post increment n plus plus] + F --> G[Return old value] + end + + subgraph StateManagement + G --> H[n updated in closure] + H --> D + end +``` + +**説明**: + +- 作成フェーズで検証とクロージャースコープ確立 +- 実行時フェーズで `n` へのアクセスとインクリメント +- 状態管理はクロージャー内で完結し、外部から直接変更不可 + +--- + +

正しさのスケッチ

+ +### 不変条件 + +**INV1**: クロージャー内の変数 `n` は常に有効な整数値を保持 +**INV2**: 各カウンターインスタンスは独立したクロージャースコープを持つ +**INV3**: `k` 回目の呼び出しは `初期値 + (k-1)` を返す(1-indexed) + +### 網羅性 + +- **基底ケース**: 初回呼び出し時 `n++` は現在の `n` を返し、その後 `n` を増加 +- **帰納ステップ**: k回目呼び出し後の状態が `初期値 + k` なら、(k+1)回目は `初期値 + k` を返し、状態は `初期値 + (k+1)` になる + +### 終了性 + +- 各呼び出しは O(1) で終了(無限ループなし) +- クロージャーの寿命はガベージコレクション管理下 + +### 独立性の証明 + +```typescript +const c1 = createCounter(5); +const c2 = createCounter(10); +c1(); // 5 (c1のスコープ内: n=6) +c2(); // 10 (c2のスコープ内: n=11) +c1(); // 6 (c1のスコープ内: n=7) +``` + +各 `createCounter` 呼び出しは新しい実行コンテキストを生成し、独立したレキシカルスコープを持つため、`c1` と `c2` は互いに影響しない。 + +--- + +

計算量

+ +### 時間計算量: O(1) + +- **createCounter**: O(1) - 入力検証とクロージャー作成 +- **counter()**: O(1) - 後置インクリメント演算(CPU命令1つ) + +### 空間計算量: O(1) + +- **補助空間**: なし +- **クロージャー変数**: 8バイト(number型)× カウンター数 + +### 比較: 代替アプローチ + +| アプローチ | 時間 | 空間 | 型安全性 | 実装複雑度 | +| --------------------------- | ---- | ---- | -------- | ---------- | +| クロージャー + `n++` | O(1) | O(1) | 高 | 最低 | +| クロージャー + カウント変数 | O(1) | O(1) | 高 | 低 | +| Class ベース | O(1) | O(1) | 高 | 中 | +| Generator 関数 | O(1) | O(1) | 中 | 中 | + +**推奨**: クロージャー + `n++` が最もシンプルで LeetCode の期待解 + +--- + +

TypeScript実装

+ +```typescript +from __future__ import annotations +from typing import Callable + +/** + * カウンター関数を生成する高階関数 + * + * @param n - カウンターの初期値 (-1000 <= n <= 1000) + * @returns 呼び出すたびにインクリメントされる値を返す関数 + * @throws {RangeError} n が制約範囲外の場合 + * @throws {TypeError} n が有限数でない場合 + * + * @complexity + * - Time: O(1) for creation and each call + * - Space: O(1) per counter instance + * + * @example + * const counter = createCounter(10); + * counter(); // 10 + * counter(); // 11 + * counter(); // 12 + */ +function createCounter(n: number): () => number { + // 入力検証: 制約条件チェック + if (n < -1000 || n > 1000) { + throw new RangeError( + `Initial value ${n} is out of bounds [-1000, 1000]` + ); + } + + // 型ガード: number型の確認 + if (typeof n !== 'number' || !Number.isFinite(n)) { + throw new TypeError( + 'Initial value must be a finite number' + ); + } + + /** + * カウンター関数(クロージャー) + * + * クロージャースコープ内の変数 n を保持し、 + * 呼び出すたびに現在値を返してから1増加させる + * + * @returns 現在のカウント値 + * + * @invariant n は常に整数値を保持 + * @invariant k回目の呼び出しは (初期値 + k - 1) を返す + */ + return function(): number { + // 後置インクリメント演算子: + // 1. 現在の n の値を評価(返却用) + // 2. n に 1 を加算(次回呼び出し用) + // 3. ステップ1の値を return + return n++; + }; +} + +// LeetCode 提出用フォーマット +const createCounterLeetCode = createCounter; + +/** + * 使用例: Example 1 + */ +const counter1 = createCounter(10); +console.assert(counter1() === 10, 'Test 1-1 failed'); +console.assert(counter1() === 11, 'Test 1-2 failed'); +console.assert(counter1() === 12, 'Test 1-3 failed'); + +/** + * 使用例: Example 2 + */ +const counter2 = createCounter(-2); +console.assert(counter2() === -2, 'Test 2-1 failed'); +console.assert(counter2() === -1, 'Test 2-2 failed'); +console.assert(counter2() === 0, 'Test 2-3 failed'); +console.assert(counter2() === 1, 'Test 2-4 failed'); +console.assert(counter2() === 2, 'Test 2-5 failed'); + +/** + * 独立性の検証 + */ +const c1 = createCounter(5); +const c2 = createCounter(10); +console.assert(c1() === 5, 'Independence test 1 failed'); +console.assert(c2() === 10, 'Independence test 2 failed'); +console.assert(c1() === 6, 'Independence test 3 failed'); +console.assert(c2() === 11, 'Independence test 4 failed'); +``` + +### LeetCode 最小提出版 + +```typescript +/** + * @param {number} n + * @return {Function} counter + */ +function createCounter(n: number): () => number { + return function (): number { + return n++; + }; +} +``` + +--- + +

TypeScript最適化ポイント

+ +### 1. 型安全性の最大化 + +**厳密な型定義**: + +```typescript +// 引数と戻り値の型を明示 +function createCounter(n: number): () => number { + // ... +} +``` + +**利点**: + +- コンパイル時に型不一致を検出 +- IDE の IntelliSense で関数シグネチャを自動表示 +- リファクタリング時の安全性向上 + +### 2. コンパイル時最適化 + +**型推論の活用**: + +```typescript +return function (): number { + return n++; // n の型は自動的に number と推論 +}; +``` + +**const assertion(この問題では不要だが応用例)**: + +```typescript +const LIMITS = { min: -1000, max: 1000 } as const; +// LIMITS.min は number ではなく -1000 型 +``` + +### 3. ランタイム最適化 + +**後置インクリメント演算子の効率性**: + +- CPU命令レベルで最適化済み(`INC` 命令など) +- 中間変数不要で最小メモリフットプリント + +**クロージャーのメモリ効率**: + +```typescript +// Bad: 不要なオブジェクト生成 +return function (): number { + const result = { value: n }; + n++; + return result.value; // 毎回オブジェクト生成 +}; + +// Good: プリミティブ型の直接操作 +return function (): number { + return n++; // オブジェクト生成なし +}; +``` + +### 4. エラーハンドリング戦略 + +**型レベルでのエラー防止**: + +```typescript +// コンパイルエラーを引き起こす例 +createCounter('10'); // Error: Argument of type 'string' is not assignable to parameter of type 'number' +``` + +**実行時検証**: + +```typescript +if (n < -1000 || n > 1000) { + throw new RangeError(/* ... */); +} +``` + +### 5. strict mode での安全性 + +**tsconfig.json 推奨設定**: + +```json +{ + "compilerOptions": { + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true + } +} +``` + +--- + +

エッジケースと検証観点

+ +### 境界値テスト + +| ケース | 入力 | 期待動作 | 理由 | +| ---------- | ----------- | ------------ | -------- | +| 最小値 | `n = -1000` | 正常動作 | 制約下限 | +| 最大値 | `n = 1000` | 正常動作 | 制約上限 | +| 最小値未満 | `n = -1001` | `RangeError` | 制約違反 | +| 最大値超過 | `n = 1001` | `RangeError` | 制約違反 | +| ゼロ | `n = 0` | 正常動作 | 境界値 | + +### 型安全性テスト + +```typescript +// 文字列を渡した場合 +try { + createCounter('10' as any); // TypeError +} catch (e) { + console.log('Caught type error'); +} + +// NaN を渡した場合 +try { + createCounter(NaN); // TypeError: not finite +} catch (e) { + console.log('Caught NaN error'); +} + +// Infinity を渡した場合 +try { + createCounter(Infinity); // TypeError: not finite +} catch (e) { + console.log('Caught Infinity error'); +} +``` + +### 独立性検証 + +```typescript +// 複数カウンターの独立性 +const counters = [createCounter(0), createCounter(100), createCounter(-50)]; + +counters[0](); // 0 +counters[1](); // 100 +counters[0](); // 1 (counters[1] の呼び出しに影響されない) +counters[2](); // -50 +``` + +### 大量呼び出しテスト + +```typescript +// 制約: calls.length <= 1000 +const counter = createCounter(0); +for (let i = 0; i < 1000; i++) { + const result = counter(); + console.assert(result === i, `Call ${i} failed`); +} +``` + +### メモリリークチェック + +```typescript +// カウンターへの参照が解放されれば GC 対象 +function testMemory() { + const counter = createCounter(0); + counter(); // 使用 + // 関数終了後、counter への参照がなくなれば GC される +} + +testMemory(); +// この時点で counter のクロージャーは GC 可能 +``` + +--- + +

FAQ

+ +### Q1: なぜ前置インクリメント (`++n`) ではなく後置インクリメント (`n++`) を使うのか? + +**A**: 問題要件により、初回呼び出しで初期値 `n` そのものを返す必要があるため。 + +```typescript +// 後置インクリメント (正解) +let n = 10; +return n++; // 10 を返し、その後 n は 11 になる + +// 前置インクリメント (誤り) +let n = 10; +return ++n; // 11 を返してしまう +``` + +### Q2: クロージャーではなく class で実装すべきケースは? + +**A**: 以下の場合は class の方が適切: + +- カウンター以外のメソッドが必要(reset, getValue など) +- 継承やポリモーフィズムが必要 +- TypeScript の private フィールドで明示的にカプセル化したい + +```typescript +class Counter { + #value: number; + + constructor(initialValue: number) { + this.#value = initialValue; + } + + call(): number { + return this.#value++; + } + + reset(): void { + this.#value = 0; + } +} +``` + +### Q3: TypeScript の型安全性は実行時パフォーマンスに影響するか? + +**A**: **しない**。TypeScript の型情報はコンパイル時のみ使用され、JavaScript へのトランスパイル後は完全に削除される。 + +```typescript +// TypeScript (型情報あり) +function createCounter(n: number): () => number { + return function (): number { + return n++; + }; +} + +// トランスパイル後の JavaScript (型情報なし) +function createCounter(n) { + return function () { + return n++; + }; +} +``` + +### Q4: `let count = 0; return () => n + count++;` のようなアプローチとの違いは? + +**A**: 不要な変数を追加している分、メモリ効率が悪い。 + +```typescript +// 非推奨: 2つの変数を保持 +function createCounter(n: number): () => number { + let count = 0; + return () => n + count++; // 8バイト × 2 +} + +// 推奨: 1つの変数のみ +function createCounter(n: number): () => number { + return () => n++; // 8バイト × 1 +} +``` + +### Q5: strict mode なしでも動作するか? + +**A**: 動作するが、型安全性のメリットが大幅に減少する。strict mode を有効にすることで: + +- `null`/`undefined` の暗黙的な混入を防止 +- 型推論の精度向上 +- より早期にバグを検出 + +```typescript +// strict: false の場合 +function createCounter(n) { + // n: any と推論される + return function () { + return n++; // n が string でもエラーにならない + }; +} + +// strict: true の場合 +function createCounter(n: number): () => number { + return function (): number { + return n++; // n は確実に number + }; +} +``` + +### Q6: Web Worker や並行処理での使用は安全か? + +**A**: 各 Web Worker は独立した実行コンテキストを持つため、同一カウンターインスタンスを共有することは不可能。ただし、SharedArrayBuffer を使えば共有カウンターを実装可能(この問題の範囲外)。 + +```typescript +// メインスレッド +const counter = createCounter(0); +worker.postMessage(counter); // 関数はシリアライズ不可 → エラー + +// 各 Worker で独立したカウンターを作成する必要がある +``` + +--- + +**まとめ**: この実装はクロージャーパターンの典型例であり、TypeScript の型安全性を活用しつつ、最小限のコードで高いパフォーマンスを実現しています。LeetCode の制約を完全に満たし、実務でも応用可能な設計となっています。 diff --git a/JavaScript/2620. Counter/Claude Code Sonnet 4.5/README_react.html b/JavaScript/2620. Counter/Claude Code Sonnet 4.5/README_react.html new file mode 100644 index 00000000..f9d78f98 --- /dev/null +++ b/JavaScript/2620. Counter/Claude Code Sonnet 4.5/README_react.html @@ -0,0 +1,1735 @@ + + + + + + LeetCode 2620: Counter - クロージャーによる状態管理 + + + + + + + + + + + + + + + + + +
+ + + + +
+

+ アルゴリズム概要 +

+ +
+
+

問題の説明

+

+ 整数 + n + を受け取り、カウンター関数を返す高階関数を実装します。 + 返されたカウンター関数は、初回呼び出し時に + n + を返し、 2回目以降は前回の値より1大きい値を返します(n+1, + n+2, ...)。 +

+
+ +
+

入出力例

+
+

+ 入力: n = 10, ["call","call","call"] +

+

+ 出力: [10, 11, 12] +

+

+ 説明:
+ counter() = 10 // 初回呼び出し、n を返す
+ counter() = 11 // 1増加した値を返す
+ counter() = 12 // さらに1増加した値を返す +

+
+
+ +
+

制約条件

+
    +
  • + -1000 <= n <= 1000 +
  • +
  • + 0 <= calls.length <= 1000 +
  • +
  • + calls[i] === "call" +
  • +
+
+ +
+

アルゴリズム戦略

+
    +
  • + + クロージャーパターン: + 外部関数のスコープ内の変数を内部関数が保持 +
  • +
  • + + 後置インクリメント: + n++ + で現在値を返してから増加 +
  • +
  • + + 状態管理: + 各カウンターインスタンスが独立した状態を保持 +
  • +
+
+ +
+

主要ポイント

+
+
+

時間計算量

+

O(1)

+

各呼び出しで定数時間

+
+
+

空間計算量

+

O(1)

+

単一の数値変数のみ

+
+
+
+
+
+ + +
+

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

+
+
+ + +
+

+ TypeScript実装 +

+
/**
+ * カウンター関数を生成する高階関数
+ *
+ * @param n - カウンターの初期値 (-1000 <= n <= 1000)
+ * @returns 呼び出すたびにインクリメントされる値を返す関数
+ * @throws {RangeError} n が制約範囲外の場合
+ * @throws {TypeError} n が有限数でない場合
+ *
+ * @complexity
+ * - Time: O(1) for creation and each call
+ * - Space: O(1) per counter instance
+ *
+ * @example
+ * const counter = createCounter(10);
+ * counter(); // 10
+ * counter(); // 11
+ * counter(); // 12
+ */
+function createCounter(n: number): () => number {
+    // 入力検証: 制約条件チェック
+    if (n < -1000 || n > 1000) {
+        throw new RangeError(
+            `Initial value ${n} is out of bounds [-1000, 1000]`
+        );
+    }
+
+    // 型ガード: number型の確認
+    if (typeof n !== 'number' || !Number.isFinite(n)) {
+        throw new TypeError(
+            'Initial value must be a finite number'
+        );
+    }
+
+    /**
+     * カウンター関数(クロージャー)
+     *
+     * クロージャースコープ内の変数 n を保持し、
+     * 呼び出すたびに現在値を返してから1増加させる
+     *
+     * @returns 現在のカウント値
+     *
+     * @invariant n は常に整数値を保持
+     * @invariant k回目の呼び出しは (初期値 + k - 1) を返す
+     */
+    return function(): number {
+        // 後置インクリメント演算子:
+        // 1. 現在の n の値を評価(返却用)
+        // 2. n に 1 を加算(次回呼び出し用)
+        // 3. ステップ1の値を return
+        return n++;
+    };
+}
+
+// LeetCode 最小提出版
+function createCounter(n: number): () => number {
+    return function(): number {
+        return n++;
+    };
+}
+
+ + +
+

+ フローチャート +

+
+ + + + + + + + + + + + + + + + + + + + 開始 createCounter(n) + + + + + + + 入力検証 + + + 範囲チェック + + + + + + いいえ + + + + エラー + + + RangeError + + + + + + はい + + + + + + クロージャー作成 + + + 変数nをスコープに保持 + + + 内部関数を返却 + + + + + + + カウンター関数返却 + + + + + + + counter() 呼び出し + + + クロージャー内のnにアクセス + + + + + + + n++ 実行 + + + 1. 現在のnを評価 + + + 2. nに1を加算 + + + + + + + 元の値を返却 + + + + + + 次回呼び出しへ + + + + + +
+ +

+ フローの説明:
+ + 1. 入力検証: n + が制約範囲内かチェック(-1000 ≤ n ≤ 1000)
+ 2. エラー処理: 範囲外の場合は + RangeError をスロー
+ 3. クロージャー作成: 変数 n + をレキシカルスコープに保持した内部関数を生成
+ 4. 関数返却: + カウンター関数を呼び出し元に返す
+ 5. counter() 呼び出し: + クロージャー内の n にアクセス
+ 6. 後置インクリメント: 現在の n + を評価してから 1 を加算
+ 7. 値を返却: 元の n の値を返す
+ 8. ループバック: + 次回呼び出し時は更新された n で再度実行 +
+

+
+ + +
+

+ 計算量分析 +

+ +
+
+

時間計算量

+
+

O(1)

+
    +
  • + + createCounter: O(1) - + 入力検証とクロージャー作成 +
  • +
  • + + counter(): O(1) - + 後置インクリメント演算(CPU命令1つ) +
  • +
+
+
+ +
+

空間計算量

+
+

O(1)

+
    +
  • + + 補助空間: なし +
  • +
  • + + クロージャー変数: 8バイト(number型)× + カウンター数 +
  • +
+
+
+ +
+

アプローチ比較

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ アプローチ + + 時間 + + 空間 + + 型安全性 + + 実装複雑度 +
+ クロージャー + n++ + + O(1) + + O(1) + + 高 + + 最低 +
+ クロージャー + カウント変数 + + O(1) + + O(1) + + 高 + + 低 +
+ Class ベース + + O(1) + + O(1) + + 高 + + 中 +
+ Generator 関数 + + O(1) + + O(1) + + 中 + + 中 +
+
+

+ 推奨: クロージャー + + n++ + が最もシンプルで LeetCode の期待解 +

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