|
| 1 | +{ |
| 2 | + "cells": [ |
| 3 | + { |
| 4 | + "cell_type": "markdown", |
| 5 | + "id": "a7571108", |
| 6 | + "metadata": {}, |
| 7 | + "source": [ |
| 8 | + "## 1. 問題の分析\n", |
| 9 | + "\n", |
| 10 | + "**競技プログラミング視点**\n", |
| 11 | + "- 配列を右から左へ1パスするだけで解決可能。`reduceRight` が最適。\n", |
| 12 | + "- 追加メモリ不要(クロージャで `x` を畳み込む)。\n", |
| 13 | + "\n", |
| 14 | + "**業務開発視点**\n", |
| 15 | + "- 空配列 → 恒等関数という仕様を型安全に表現できる。\n", |
| 16 | + "- `readonly` 修飾子で入力配列の不変性を保証。\n", |
| 17 | + "\n", |
| 18 | + "**TypeScript特有の考慮点**\n", |
| 19 | + "- `F = (x: number) => number` という型エイリアスがすでに与えられているため、ジェネリクス不要。\n", |
| 20 | + "- `reduceRight` の型推論が自然に効く。\n", |
| 21 | + "\n", |
| 22 | + "---\n", |
| 23 | + "\n", |
| 24 | + "## 2. アルゴリズムアプローチ比較\n", |
| 25 | + "\n", |
| 26 | + "| アプローチ | 時間計算量 | 空間計算量 | TS実装コスト | 型安全性 | 可読性 | 備考 |\n", |
| 27 | + "|---|---|---|---|---|---|---|\n", |
| 28 | + "| `reduceRight` | O(n) | O(1) | 低 | 高 | 高 | 最もシンプル |\n", |
| 29 | + "| `for` ループ(右→左) | O(n) | O(1) | 低 | 高 | 中 | 命令的 |\n", |
| 30 | + "| 再帰 | O(n) | O(n) | 中 | 高 | 中 | スタックオーバーフローリスク |\n", |
| 31 | + "\n", |
| 32 | + "---\n", |
| 33 | + "\n", |
| 34 | + "## 3. 選択したアルゴリズムと理由\n", |
| 35 | + "\n", |
| 36 | + "- **選択**: `reduceRight`\n", |
| 37 | + "- **理由**:\n", |
| 38 | + " - 数学的な「右から左への関数合成」を宣言的に表現でき、可読性・意図の明確さが最高。\n", |
| 39 | + " - O(n) / O(1) で計算量も最適。\n", |
| 40 | + " - TypeScriptの型推論が自然に効き、型注釈の追加が不要。\n", |
| 41 | + "\n", |
| 42 | + "---\n", |
| 43 | + "\n", |
| 44 | + "## 4. 実装コード" |
| 45 | + ] |
| 46 | + }, |
| 47 | + { |
| 48 | + "cell_type": "code", |
| 49 | + "execution_count": null, |
| 50 | + "id": "implementation", |
| 51 | + "metadata": {}, |
| 52 | + "outputs": [], |
| 53 | + "source": [ |
| 54 | + "// Analyze Complexity\n", |
| 55 | + "// Runtime 56 ms\n", |
| 56 | + "// Beats 55.84%\n", |
| 57 | + "// Memory 56.88 MB\n", |
| 58 | + "// Beats 46.50%\n", |
| 59 | + "type F = (x: number) => number;\n", |
| 60 | + "\n", |
| 61 | + "/**\n", |
| 62 | + " * 関数配列の右から左への合成を返す\n", |
| 63 | + " * @param functions - 合成する関数の配列\n", |
| 64 | + " * @returns 合成された関数。空配列の場合は恒等関数\n", |
| 65 | + " * @complexity Time: O(n), Space: O(1)\n", |
| 66 | + " */\n", |
| 67 | + "function compose(functions: readonly F[]): F {\n", |
| 68 | + " return function (x: number): number {\n", |
| 69 | + " return functions.reduceRight(\n", |
| 70 | + " (acc: number, fn: F): number => fn(acc),\n", |
| 71 | + " x\n", |
| 72 | + " );\n", |
| 73 | + " };\n", |
| 74 | + "}\n", |
| 75 | + "\n", |
| 76 | + "// 動作確認\n", |
| 77 | + "const fn1 = compose([x => x + 1, x => x * x, x => 2 * x]);\n", |
| 78 | + "console.log(\"Example 1 (x=4): 2*4=8 -> 8*8=64 -> 64+1=65 :\", fn1(4));\n", |
| 79 | + "\n", |
| 80 | + "const fn2 = compose([x => 10 * x, x => 10 * x, x => 10 * x]);\n", |
| 81 | + "console.log(\"Example 2 (x=1): 10 -> 100 -> 1000 :\", fn2(1));\n", |
| 82 | + "\n", |
| 83 | + "const fn3 = compose([]);\n", |
| 84 | + "console.log(\"Example 3 (x=42): 42 :\", fn3(42));\n", |
| 85 | + "\n", |
| 86 | + "// Interactive checks\n", |
| 87 | + "compose([x => x + 1, x => 2 * x])(4)" |
| 88 | + ] |
| 89 | + }, |
| 90 | + { |
| 91 | + "cell_type": "markdown", |
| 92 | + "id": "points", |
| 93 | + "metadata": {}, |
| 94 | + "source": [ |
| 95 | + "**ポイント:**\n", |
| 96 | + "- `functions` を `readonly F[]` とすることで入力配列の不変性を型レベルで保証。\n", |
| 97 | + "- `reduceRight` の初期値 `x` が空配列時の恒等関数の役割を自然に担うため、空配列の特別処理が不要。\n", |
| 98 | + "- コールバック内の引数 `acc`・`fn` に型注釈を付与し、strict mode 下でも型推論が確実に機能。" |
| 99 | + ] |
| 100 | + } |
| 101 | + ], |
| 102 | + "metadata": { |
| 103 | + "kernelspec": { |
| 104 | + "display_name": "TypeScript", |
| 105 | + "language": "typescript", |
| 106 | + "name": "typescript" |
| 107 | + }, |
| 108 | + "language_info": { |
| 109 | + "file_extension": ".ts", |
| 110 | + "mimetype": "text/typescript", |
| 111 | + "name": "typescript", |
| 112 | + "version": "5.9.3" |
| 113 | + } |
| 114 | + }, |
| 115 | + "nbformat": 4, |
| 116 | + "nbformat_minor": 5 |
| 117 | +} |
0 commit comments