Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 214 additions & 0 deletions JavaScript/2620. Counter/Claude Code Sonnet 4.5/Counter_TS.ipynb
Original file line number Diff line number Diff line change
@@ -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
}
Loading