-
Notifications
You must be signed in to change notification settings - Fork 0
Add JavaScript/2626. Array Reduce Transformation #261
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,395 @@ | ||
| { | ||
| "cells": [ | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "c1a3e2d9", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "# TypeScript Reduce関数の実装\n", | ||
| "\n", | ||
| "## 1. 問題の分析\n", | ||
| "\n", | ||
| "### 競技プログラミング視点での分析\n", | ||
| "- **実行速度**: 配列を1回走査するだけの単純な反復処理(O(n))\n", | ||
| "- **メモリ効率**: 追加のデータ構造が不要、累積値のみを保持(O(1))\n", | ||
| "- **最適化ポイント**: ループ方式の選択(for vs forEach vs for-of)\n", | ||
| "\n", | ||
| "### 業務開発視点での分析\n", | ||
| "- **型安全性**: 関数型引数とジェネリクスによる型保証が重要\n", | ||
| "- **可読性**: reduceの動作を明確に示す実装\n", | ||
| "- **エラーハンドリング**: 空配列の処理、null/undefined安全性\n", | ||
| "- **保守性**: シンプルで理解しやすいコード\n", | ||
| "\n", | ||
| "### TypeScript特有の考慮点\n", | ||
| "- **型推論**: `Fn`型の厳密な定義により、コンパイル時に型エラーを検出\n", | ||
| "- **イミュータビリティ**: 元の配列を変更しない純粋関数\n", | ||
| "- **null安全性**: strict modeでの安全な実装\n", | ||
| "\n", | ||
| "## 2. アルゴリズムアプローチ比較\n", | ||
| "\n", | ||
| "| アプローチ | 時間計算量 | 空間計算量 | TS実装コスト | 型安全性 | 可読性 | 備考 |\n", | ||
| "|---------|----------|---------|------------|---------|-------|------|\n", | ||
| "| forループ | O(n) | O(1) | 低 | 高 | 高 | 最も基本的で高速 |\n", | ||
| "| for-ofループ | O(n) | O(1) | 低 | 高 | 高 | モダンな構文、若干遅い |\n", | ||
| "| forEachメソッド | O(n) | O(1) | 低 | 高 | 中 | 関数呼び出しオーバーヘッド |\n", | ||
| "| 再帰 | O(n) | O(n) | 中 | 高 | 中 | スタックオーバーフローリスク |\n", | ||
| "\n", | ||
| "## 3. 選択したアルゴリズムと理由\n", | ||
| "\n", | ||
| "### 選択したアプローチ: **forループ**\n", | ||
| "\n", | ||
| "### 理由\n", | ||
| "1. **計算量的な優位性**\n", | ||
| " - 時間: O(n) - 配列を1回走査\n", | ||
| " - 空間: O(1) - 累積値のみを保持\n", | ||
| " - インデックスベースのアクセスで最速\n", | ||
| "\n", | ||
| "2. **TypeScript環境での型安全性**\n", | ||
| " - コンパイル時に型チェックが完全に機能\n", | ||
| " - 累積値の型が明確に推論される\n", | ||
| " - 副作用なしの純粋関数として実装可能\n", | ||
| "\n", | ||
| "3. **保守性・可読性の観点**\n", | ||
| " - reduce操作の意図が明確\n", | ||
| " - デバッグが容易\n", | ||
| " - エッジケース(空配列)の処理が明示的\n", | ||
| "\n", | ||
| "### TypeScript特有の最適化ポイント\n", | ||
| "- **型アノテーション**: 累積値の型が自動推論されるため、型注釈が最小限\n", | ||
| "- **const使用**: イミュータビリティの確保\n", | ||
| "- **早期リターン**: 空配列チェックによる不要な処理の回避\n", | ||
| "\n", | ||
| "## 4. 実装コード\n", | ||
| "\n", | ||
| "```typescript\n", | ||
| "// Analyze Complexity\n", | ||
| "// Runtime 51 ms\n", | ||
| "// Beats 31.36%\n", | ||
| "// Memory 56.13 MB\n", | ||
| "// Beats 50.75%\n", | ||
| "\n", | ||
| "type Fn = (accum: number, curr: number) => number\n", | ||
| "\n", | ||
| "/**\n", | ||
| " * 配列の各要素に対してreducer関数を順次適用し、単一の累積値を返す\n", | ||
| " * \n", | ||
| " * @param nums - 処理対象の数値配列\n", | ||
| " * @param fn - 累積値と現在値を受け取り、新しい累積値を返すreducer関数\n", | ||
| " * @param init - 初期累積値\n", | ||
| " * @returns 全要素に対してfnを適用した最終的な累積値\n", | ||
| " * @complexity Time: O(n), Space: O(1)\n", | ||
| " * \n", | ||
| " * @example\n", | ||
| " * reduce([1,2,3,4], (acc, curr) => acc + curr, 0) // returns 10\n", | ||
| " * reduce([], (acc, curr) => acc + curr, 25) // returns 25\n", | ||
| " */\n", | ||
| "function reduce(nums: number[], fn: Fn, init: number): number {\n", | ||
| " // 早期リターン: 空配列の場合は初期値をそのまま返す\n", | ||
| " if (nums.length === 0) {\n", | ||
| " return init;\n", | ||
| " }\n", | ||
| " \n", | ||
| " // 累積値を初期値で初期化\n", | ||
| " let accumulator: number = init;\n", | ||
| " \n", | ||
| " // 配列の各要素に対してreducer関数を順次適用\n", | ||
| " for (let i = 0; i < nums.length; i++) {\n", | ||
| " accumulator = fn(accumulator, nums[i]);\n", | ||
| " }\n", | ||
| " \n", | ||
| " // 最終的な累積値を返す\n", | ||
| " return accumulator;\n", | ||
| "}\n", | ||
| "```\n", | ||
| "\n", | ||
| "### 代替実装(より関数型的なアプローチ)\n", | ||
| "\n", | ||
| "```typescript\n", | ||
| "// Analyze Complexity\n", | ||
| "// Runtime 43 ms\n", | ||
| "// Beats 75.08%\n", | ||
| "// Memory 58.72 MB\n", | ||
| "// Beats 5.23%\n", | ||
| "/**\n", | ||
| " * for-ofループを使用した実装\n", | ||
| " * より読みやすいが、わずかに遅い可能性がある\n", | ||
| " */\n", | ||
| "function reduceAlternative(nums: number[], fn: Fn, init: number): number {\n", | ||
| " let accumulator: number = init;\n", | ||
| " \n", | ||
| " for (const num of nums) {\n", | ||
| " accumulator = fn(accumulator, num);\n", | ||
| " }\n", | ||
| " \n", | ||
| " return accumulator;\n", | ||
| "}\n", | ||
| "```\n", | ||
| "\n", | ||
| "## LeetCode提出用コード\n", | ||
| "\n", | ||
| "```typescript\n", | ||
| "// Analyze Complexity\n", | ||
| "// Runtime 44 ms\n", | ||
| "// Beats 70.65%\n", | ||
| "// Memory 56.58 MB\n", | ||
| "// Beats 26.43%\n", | ||
| "type Fn = (accum: number, curr: number) => number\n", | ||
| "\n", | ||
| "function reduce(nums: number[], fn: Fn, init: number): number {\n", | ||
| " let accumulator = init;\n", | ||
| " for (let i = 0; i < nums.length; i++) {\n", | ||
| " accumulator = fn(accumulator, nums[i]);\n", | ||
| " }\n", | ||
| " return accumulator;\n", | ||
| "}\n", | ||
| "```\n", | ||
| "\n", | ||
| "## 実装の特徴\n", | ||
| "\n", | ||
| "### 型安全性\n", | ||
| "- ✅ `Fn`型により、reducer関数のシグネチャが厳密に定義\n", | ||
| "- ✅ `number`型の一貫性が保証される\n", | ||
| "- ✅ コンパイル時に型エラーを検出\n", | ||
| "\n", | ||
| "### パフォーマンス\n", | ||
| "- ✅ O(n)の時間計算量 - 最適\n", | ||
| "- ✅ O(1)の空間計算量 - メモリ効率的\n", | ||
| "- ✅ ループオーバーヘッドが最小\n", | ||
| "\n", | ||
| "### エッジケース処理\n", | ||
| "- ✅ 空配列 → `init`を返す\n", | ||
| "- ✅ 単一要素 → `fn(init, nums[0])`を返す\n", | ||
| "- ✅ 制約条件(0 ≤ length ≤ 1000)を満たす\n", | ||
| "\n", | ||
| "この実装は、TypeScriptの型安全性を活かしながら、最高のパフォーマンスと可読性を実現しています。" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "2bcb244c", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "# パフォーマンス分析と改善提案\n", | ||
| "\n", | ||
| "## 結果の分析\n", | ||
| "\n", | ||
| "### 興味深い発見\n", | ||
| "1. **空配列チェックのオーバーヘッド**: 早期リターンを追加したことで逆に遅くなっている(51ms vs 44ms)\n", | ||
| "2. **for-ofの優位性**: 意外にもfor-ofループが最速(43ms)だが、メモリ使用量が多い\n", | ||
| "3. **トレードオフ**: 速度とメモリのバランス\n", | ||
| "\n", | ||
| "### 問題点\n", | ||
| "- 空配列チェックは制約条件(0 ≤ length ≤ 1000)では頻繁に発生しないため、分岐予測ミスのコストの方が高い\n", | ||
| "- V8エンジンの最適化において、シンプルなコードの方が効率的\n", | ||
| "\n", | ||
| "## 改善版実装\n", | ||
| "\n", | ||
| "### 最適化版1: 最小限のコード(速度重視)\n", | ||
| "\n", | ||
| "```typescript\n", | ||
| "// Analyze Complexity\n", | ||
| "// Runtime 46 ms\n", | ||
| "// Beats 59.80%\n", | ||
| "// Memory 56.44 MB\n", | ||
| "// Beats 30.85%\n", | ||
| "type Fn = (accum: number, curr: number) => number\n", | ||
| "\n", | ||
| "function reduce(nums: number[], fn: Fn, init: number): number {\n", | ||
| " let val = init;\n", | ||
| " for (let i = 0; i < nums.length; i++) {\n", | ||
| " val = fn(val, nums[i]);\n", | ||
| " }\n", | ||
| " return val;\n", | ||
| "}\n", | ||
| "```\n", | ||
| "\n", | ||
| "**改善ポイント**:\n", | ||
| "- ✅ 空配列チェックを削除(オーバーヘッド削減)\n", | ||
| "- ✅ 変数名を短縮(`accumulator` → `val`)でメモリアクセス最適化\n", | ||
| "- ✅ 極限までシンプルに\n", | ||
| "\n", | ||
| "**予想パフォーマンス**: Runtime ~42-45ms, Memory ~55-56MB\n", | ||
| "\n", | ||
| "---\n", | ||
| "\n", | ||
| "### 最適化版2: キャッシング活用(速度最重視)\n", | ||
| "\n", | ||
| "```typescript\n", | ||
| "// Analyze Complexity\n", | ||
| "// Runtime 40 ms\n", | ||
| "// Beats 86.03%\n", | ||
| "// Memory 56.20 MB\n", | ||
| "// Beats 43.12%\n", | ||
| "type Fn = (accum: number, curr: number) => number\n", | ||
| "\n", | ||
| "function reduce(nums: number[], fn: Fn, init: number): number {\n", | ||
| " let val = init;\n", | ||
| " const len = nums.length;\n", | ||
| " for (let i = 0; i < len; i++) {\n", | ||
| " val = fn(val, nums[i]);\n", | ||
| " }\n", | ||
| " return val;\n", | ||
| "}\n", | ||
| "```\n", | ||
| "\n", | ||
| "**改善ポイント**:\n", | ||
| "- ✅ `nums.length`をキャッシュして、ループ毎のプロパティアクセスを削減\n", | ||
| "- ✅ V8の最適化を促進\n", | ||
| "\n", | ||
| "**予想パフォーマンス**: Runtime ~40-43ms, Memory ~55-56MB\n", | ||
| "\n", | ||
| "---\n", | ||
| "\n", | ||
| "### 最適化版3: アンローリング(極限の最適化)\n", | ||
| "\n", | ||
| "```typescript\n", | ||
| "// Analyze Complexity\n", | ||
| "// Runtime 47 ms\n", | ||
| "// Beats 53.17%\n", | ||
| "// Memory 56.15 MB\n", | ||
| "// Beats 50.75%\n", | ||
| "\n", | ||
| "type Fn = (accum: number, curr: number) => number\n", | ||
| "\n", | ||
| "function reduce(nums: number[], fn: Fn, init: number): number {\n", | ||
| " let val = init;\n", | ||
| " let i = 0;\n", | ||
| " const len = nums.length;\n", | ||
| " \n", | ||
| " // ループアンローリング: 4要素ずつ処理\n", | ||
| " const unrollLimit = len - (len % 4);\n", | ||
| " for (; i < unrollLimit; i += 4) {\n", | ||
| " val = fn(val, nums[i]);\n", | ||
| " val = fn(val, nums[i + 1]);\n", | ||
| " val = fn(val, nums[i + 2]);\n", | ||
| " val = fn(val, nums[i + 3]);\n", | ||
| " }\n", | ||
| " \n", | ||
| " // 残りの要素を処理\n", | ||
| " for (; i < len; i++) {\n", | ||
| " val = fn(val, nums[i]);\n", | ||
| " }\n", | ||
| " \n", | ||
| " return val;\n", | ||
| "}\n", | ||
| "```\n", | ||
|
Comment on lines
+243
to
+275
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ループアンローリングの結果が主張と矛盾しています。 実測値(47ms)がキャッシング版(40ms)より遅いにもかかわらず、「ブランチ予測とパイプライン効率を向上」「ループオーバーヘッドを75%削減」と記述されています。JITコンパイラが既にこの種の最適化を行うため、手動アンローリングは逆効果になることが多いです。実測結果に基づく注意書きを追加するか、予想パフォーマンスの記述を修正してください。 🤖 Prompt for AI Agents |
||
| "\n", | ||
| "**改善ポイント**:\n", | ||
| "- ✅ ループアンローリングでブランチ予測とパイプライン効率を向上\n", | ||
| "- ✅ 4要素ずつ処理することで、ループオーバーヘッドを75%削減\n", | ||
| "\n", | ||
| "**予想パフォーマンス**: Runtime ~38-42ms(大きな配列で効果大)\n", | ||
| "\n", | ||
| "---\n", | ||
| "\n", | ||
| "## 推奨実装\n", | ||
| "\n", | ||
| "### 🏆 ベストバランス版(推奨)\n", | ||
| "\n", | ||
| "```typescript\n", | ||
| "// Analyze Complexity\n", | ||
| "// Runtime 42 ms\n", | ||
| "// Beats 79.60%\n", | ||
| "// Memory 56.62 MB\n", | ||
| "// Beats 23.42%\n", | ||
| "type Fn = (accum: number, curr: number) => number\n", | ||
| "\n", | ||
| "function reduce(nums: number[], fn: Fn, init: number): number {\n", | ||
| " let val = init;\n", | ||
| " const len = nums.length;\n", | ||
| " for (let i = 0; i < len; i++) {\n", | ||
| " val = fn(val, nums[i]);\n", | ||
| " }\n", | ||
| " return val;\n", | ||
| "}\n", | ||
| "```\n", | ||
| "\n", | ||
| "**選択理由**:\n", | ||
| "1. **速度**: lengthキャッシングで ~5-10%高速化\n", | ||
| "2. **メモリ**: 最小限の変数使用\n", | ||
| "3. **可読性**: 十分にシンプルで理解しやすい\n", | ||
| "4. **保守性**: 過度な最適化による複雑性なし\n", | ||
| "\n", | ||
| "**期待結果**: Runtime 40-43ms (80%+), Memory 55-56MB (60%+)\n", | ||
| "\n", | ||
| "---\n", | ||
| "\n", | ||
| "## さらなる最適化のヒント\n", | ||
| "\n", | ||
| "### V8エンジン最適化のベストプラクティス\n", | ||
| "\n", | ||
| "```typescript\n", | ||
| "type Fn = (accum: number, curr: number) => number\n", | ||
| "\n", | ||
| "function reduce(nums: number[], fn: Fn, init: number): number {\n", | ||
| " // 型の一貫性を保つ(V8の隠しクラス最適化)\n", | ||
| " let val: number = init;\n", | ||
| " \n", | ||
| " // プロパティアクセスを削減\n", | ||
| " const length: number = nums.length;\n", | ||
| " \n", | ||
| " // モノモーフィックなループ(常に同じ型)\n", | ||
| " for (let i: number = 0; i < length; i++) {\n", | ||
| " val = fn(val, nums[i]);\n", | ||
| " }\n", | ||
| " \n", | ||
| " return val;\n", | ||
| "}\n", | ||
| "```\n", | ||
| "\n", | ||
| "### TypeScriptコンパイラ最適化\n", | ||
| "\n", | ||
| "tsconfig.jsonで以下を設定:\n", | ||
| "```json\n", | ||
| "{\n", | ||
| " \"compilerOptions\": {\n", | ||
| " \"target\": \"ES2022\",\n", | ||
| " \"module\": \"ES2022\",\n", | ||
| " \"strict\": true,\n", | ||
| " \"noUncheckedIndexedAccess\": false,\n", | ||
| " \"skipLibCheck\": true\n", | ||
| " }\n", | ||
| "}\n", | ||
| "```\n", | ||
|
Comment on lines
+340
to
+353
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
ノートブック前半で型安全性を重視する旨を強調していますが、 🤖 Prompt for AI Agents |
||
| "\n", | ||
| "---\n", | ||
| "\n", | ||
| "## パフォーマンス比較予測\n", | ||
| "\n", | ||
| "| 実装 | Runtime予測 | Memory予測 | 複雑度 | 推奨度 |\n", | ||
| "|------|-------------|------------|--------|--------|\n", | ||
| "| 現在のメイン実装 | 51ms (31%) | 56.13MB (51%) | 低 | ⭐⭐ |\n", | ||
| "| 最適化版1(最小限) | 42-45ms (70-80%) | 55-56MB (60%) | 低 | ⭐⭐⭐⭐ |\n", | ||
| "| 最適化版2(キャッシング) | 40-43ms (75-85%) | 55-56MB (60%) | 低 | ⭐⭐⭐⭐⭐ |\n", | ||
| "| 最適化版3(アンローリング) | 38-42ms (80-90%) | 56-57MB (50%) | 高 | ⭐⭐⭐ |\n", | ||
| "\n", | ||
| "---\n", | ||
| "\n", | ||
| "## 結論\n", | ||
| "\n", | ||
| "**最も推奨する実装は「最適化版2(キャッシング活用)」です。**\n", | ||
| "\n", | ||
| "この実装により、以下の改善が期待できます:\n", | ||
| "- ✅ Runtime: 51ms → 40-43ms(約20%改善、75-85%にランクアップ)\n", | ||
| "- ✅ Memory: ほぼ変わらず(55-56MB、60%前後)\n", | ||
| "- ✅ 可読性: 維持\n", | ||
| "- ✅ 保守性: 維持" | ||
| ] | ||
| } | ||
| ], | ||
| "metadata": { | ||
| "kernelspec": { | ||
| "display_name": "TypeScript", | ||
| "language": "typescript", | ||
| "name": "typescript" | ||
| }, | ||
| "language_info": { | ||
| "file_extension": ".ts", | ||
| "mimetype": "text/typescript", | ||
| "name": "typescript", | ||
| "version": "5.3.3" | ||
| } | ||
| }, | ||
| "nbformat": 4, | ||
| "nbformat_minor": 5 | ||
| } | ||
|
Comment on lines
+380
to
+395
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial ノートブック全体がMarkdownセルのみで構成されており、実行可能なコードセルがありません。 kernelが 🤖 Prompt for AI Agents |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
変数名の短縮が「メモリアクセス最適化」になるという主張は不正確です。
V8エンジンではJITコンパイル後に変数名は使用されないため、
accumulator→valへの変更はランタイムパフォーマンスに影響しません。可読性やコードの簡潔さとして説明するのが正確です。🤖 Prompt for AI Agents