Skip to content

Commit 2df4bb7

Browse files
authored
Merge pull request #242 from myoshi2891/dev-from-macmini
feat: add solution and documentation for LeetCode 2620. Counter
2 parents e22ef0a + 17483e7 commit 2df4bb7

3 files changed

Lines changed: 2515 additions & 0 deletions

File tree

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "9b8b80fb",
6+
"metadata": {},
7+
"source": [
8+
"# TypeScript Counter 問題の完全解析\n",
9+
"\n",
10+
"## 1. 問題の分析\n",
11+
"\n",
12+
"### 競技プログラミング視点での分析\n",
13+
"- **実行速度最優先**: クロージャーを利用した O(1) の定数時間アクセス\n",
14+
"- **メモリ使用量**: 単一の数値変数のみを保持 (O(1) 空間)\n",
15+
"- **最適化ポイント**: プリミティブ型の直接操作、不要なオブジェクト生成の回避\n",
16+
"\n",
17+
"### 業務開発視点での分析\n",
18+
"- **型安全性**: 引数と戻り値の厳密な型定義が必要\n",
19+
"- **保守性**: クロージャーの仕組みを明確にドキュメント化\n",
20+
"- **エラーハンドリング**: 制約条件 (-1000 ≤ n ≤ 1000) のバリデーション\n",
21+
"- **予測可能性**: Pure function ではなく状態を持つが、副作用は限定的\n",
22+
"\n",
23+
"### TypeScript特有の考慮点\n",
24+
"- **型推論の活用**: 戻り値の型を明示的に定義\n",
25+
"- **ジェネリクス**: この問題では不要(number型固定)\n",
26+
"- **型ガード**: 入力値の範囲検証\n",
27+
"- **クロージャー型定義**: 関数型の明示的な型注釈\n",
28+
"\n",
29+
"## 2. アルゴリズムアプローチ比較\n",
30+
"\n",
31+
"| アプローチ | 時間計算量 | 空間計算量 | TS実装コスト | 型安全性 | 可読性 | 備考 |\n",
32+
"|---------|----------|----------|------------|---------|--------|------|\n",
33+
"| クロージャー + 後置インクリメント | O(1) | O(1) | 低 | 高 | 高 | 最もシンプル、LeetCodeの想定解 |\n",
34+
"| クロージャー + 前置インクリメント | O(1) | O(1) | 低 | 高 | 中 | 初回呼び出し時の処理が複雑化 |\n",
35+
"| オブジェクト指向 (class) | O(1) | O(1) | 中 | 高 | 中 | 過剰設計、LeetCode形式に不適 |\n",
36+
"| Generator関数 | O(1) | O(1) | 中 | 中 | 低 | 呼び出し形式が異なる |\n",
37+
"\n",
38+
"## 3. 選択したアルゴリズムと理由\n",
39+
"\n",
40+
"### 選択したアプローチ\n",
41+
"**クロージャー + 後置インクリメント (n++) 方式**\n",
42+
"\n",
43+
"### 理由\n",
44+
"\n",
45+
"#### 計算量的な優位性\n",
46+
"- 時間計算量: O(1) - 各呼び出しで定数時間\n",
47+
"- 空間計算量: O(1) - 単一の数値変数のみ\n",
48+
"- インクリメント演算は CPU レベルで最適化済み\n",
49+
"\n",
50+
"#### TypeScript環境での型安全性\n",
51+
"- 引数 `n: number` の厳密な型定義\n",
52+
"- 戻り値の関数型を明示: `() => number`\n",
53+
"- コンパイル時に型不一致を検出可能\n",
54+
"\n",
55+
"#### 保守性・可読性の観点\n",
56+
"- クロージャーパターンは JavaScript/TypeScript の標準的なイディオム\n",
57+
"- 後置インクリメント (`n++`) により「現在値を返してから増加」が自明\n",
58+
"- コード量が最小で理解しやすい\n",
59+
"\n",
60+
"### TypeScript特有の最適化ポイント\n",
61+
"- **厳密な型定義**: strict mode でのコンパイル時検証\n",
62+
"- **readonly 不要**: クロージャー内の変数は外部から直接アクセス不可\n",
63+
"- **型推論の活用**: 内部変数 `n` の型は自動推論される\n",
64+
"\n",
65+
"## 4. 実装コード\n",
66+
"\n",
67+
"```typescript\n",
68+
"/**\n",
69+
" * カウンター関数を生成する\n",
70+
" * 初回呼び出し時は初期値nを返し、以降呼び出すたびに1ずつ増加した値を返す\n",
71+
" * \n",
72+
" * @param n - カウンターの初期値 (-1000 <= n <= 1000)\n",
73+
" * @returns 呼び出すたびにインクリメントされる値を返す関数\n",
74+
" * @throws {RangeError} nが制約範囲外の場合\n",
75+
" * @complexity Time: O(1), Space: O(1)\n",
76+
" * \n",
77+
" * @example\n",
78+
" * const counter = createCounter(10);\n",
79+
" * counter(); // 10\n",
80+
" * counter(); // 11\n",
81+
" * counter(); // 12\n",
82+
" */\n",
83+
"function createCounter(n: number): () => number {\n",
84+
" // 入力検証: 制約条件のチェック\n",
85+
" if (n < -1000 || n > 1000) {\n",
86+
" throw new RangeError('Initial value must be between -1000 and 1000');\n",
87+
" }\n",
88+
" \n",
89+
" // 型ガード: number型の確認\n",
90+
" if (typeof n !== 'number' || !Number.isFinite(n)) {\n",
91+
" throw new TypeError('Initial value must be a finite number');\n",
92+
" }\n",
93+
" \n",
94+
" /**\n",
95+
" * クロージャーによるカウンター実装\n",
96+
" * 外部スコープの変数nを保持し、呼び出すたびにインクリメント\n",
97+
" * \n",
98+
" * @returns 現在のカウント値(呼び出し後に内部状態が+1される)\n",
99+
" */\n",
100+
" return function(): number {\n",
101+
" // 後置インクリメント: 現在値を返した後にnを+1\n",
102+
" // この演算子により「返却」→「増加」の順序が保証される\n",
103+
" return n++;\n",
104+
" };\n",
105+
"}\n",
106+
"\n",
107+
"// LeetCode形式のエクスポート(互換性のため)\n",
108+
"const createCounterLeetCode = createCounter;\n",
109+
"\n",
110+
"/**\n",
111+
" * 使用例とテストケース\n",
112+
" */\n",
113+
"// Example 1\n",
114+
"const counter1 = createCounter(10);\n",
115+
"console.assert(counter1() === 10, 'First call should return 10');\n",
116+
"console.assert(counter1() === 11, 'Second call should return 11');\n",
117+
"console.assert(counter1() === 12, 'Third call should return 12');\n",
118+
"\n",
119+
"// Example 2\n",
120+
"const counter2 = createCounter(-2);\n",
121+
"console.assert(counter2() === -2, 'First call should return -2');\n",
122+
"console.assert(counter2() === -1, 'Second call should return -1');\n",
123+
"console.assert(counter2() === 0, 'Third call should return 0');\n",
124+
"console.assert(counter2() === 1, 'Fourth call should return 1');\n",
125+
"console.assert(counter2() === 2, 'Fifth call should return 2');\n",
126+
"\n",
127+
"// エッジケース\n",
128+
"const counterMin = createCounter(-1000);\n",
129+
"console.assert(counterMin() === -1000, 'Minimum value test');\n",
130+
"\n",
131+
"const counterMax = createCounter(1000);\n",
132+
"console.assert(counterMax() === 1000, 'Maximum value test');\n",
133+
"```\n",
134+
"\n",
135+
"## LeetCode提出用フォーマット\n",
136+
"\n",
137+
"```typescript\n",
138+
"// Analyze Complexity\n",
139+
"// Runtime 43 ms\n",
140+
"// Beats 57.94%\n",
141+
"// Memory 53.82 MB\n",
142+
"// Beats 89.21%\n",
143+
"\n",
144+
"/**\n",
145+
" * @param {number} n\n",
146+
" * @return {Function} counter\n",
147+
" */\n",
148+
"function createCounter(n: number): () => number {\n",
149+
" return function(): number {\n",
150+
" return n++;\n",
151+
" };\n",
152+
"}\n",
153+
"\n",
154+
"/** \n",
155+
" * const counter = createCounter(10)\n",
156+
" * counter() // 10\n",
157+
" * counter() // 11\n",
158+
" * counter() // 12\n",
159+
" */\n",
160+
"```\n",
161+
"\n",
162+
"## TypeScript固有の最適化観点\n",
163+
"\n",
164+
"### 型安全性の活用\n",
165+
"\n",
166+
"1. **コンパイル時エラー防止**\n",
167+
" - `n: number` により文字列や他の型の混入を防止\n",
168+
" - `() => number` により戻り値の型不一致を検出\n",
169+
" - strict モードで `null`/`undefined` の混入を防止\n",
170+
"\n",
171+
"2. **実行時型検証**\n",
172+
" ```typescript\n",
173+
" if (typeof n !== 'number' || !Number.isFinite(n)) {\n",
174+
" throw new TypeError('Invalid input type');\n",
175+
" }\n",
176+
" ```\n",
177+
"\n",
178+
"3. **型推論の活用**\n",
179+
" - クロージャー内の `n` は自動的に `number` 型と推論される\n",
180+
" - 明示的な型注釈が不要で冗長性を削減\n",
181+
"\n",
182+
"### パフォーマンス最適化\n",
183+
"\n",
184+
"1. **プリミティブ型の直接操作**\n",
185+
" - オブジェクト生成のオーバーヘッドなし\n",
186+
" - 後置インクリメント演算子は CPU レベルで最適化\n",
187+
"\n",
188+
"2. **クロージャーの効率的利用**\n",
189+
" - 変数 `n` はヒープではなくクロージャースコープに保持\n",
190+
" - ガベージコレクションの対象が最小化\n",
191+
"\n",
192+
"3. **不要な処理の排除**\n",
193+
" - 条件分岐なし\n",
194+
" - 配列やオブジェクトの生成なし\n",
195+
"\n",
196+
"### 保守性と開発効率\n",
197+
"\n",
198+
"- **IntelliSense サポート**: 関数の型情報が IDE で自動表示\n",
199+
"- **リファクタリング安全性**: 型定義により変更影響範囲を把握\n",
200+
"- **自己文書化**: JSDoc コメントと型定義でドキュメント不要\n",
201+
"- **テスト容易性**: Pure な入出力で単体テストが簡単\n",
202+
"\n",
203+
"この実装は、LeetCode の制約条件を満たしつつ、TypeScript の型安全性を最大限活用した最適解となっています。"
204+
]
205+
}
206+
],
207+
"metadata": {
208+
"language_info": {
209+
"name": "python"
210+
}
211+
},
212+
"nbformat": 4,
213+
"nbformat_minor": 5
214+
}

0 commit comments

Comments
 (0)