|
| 1 | +{ |
| 2 | + "cells": [ |
| 3 | + { |
| 4 | + "cell_type": "markdown", |
| 5 | + "id": "464fa3b5", |
| 6 | + "metadata": {}, |
| 7 | + "source": [ |
| 8 | + "# Python コーディング問題: Plus One\n", |
| 9 | + "\n", |
| 10 | + "## 1. 問題分析結果\n", |
| 11 | + "\n", |
| 12 | + "### 競技プログラミング視点\n", |
| 13 | + "\n", |
| 14 | + "- **制約分析**: \n", |
| 15 | + " - 配列長: 1 ≤ len(digits) ≤ 100 → O(n)アルゴリズムで十分\n", |
| 16 | + " - 各要素: 0 ≤ digits[i] ≤ 9 → 整数演算のみで処理可能\n", |
| 17 | + " - 先頭に0なし → エッジケース考慮が簡素化\n", |
| 18 | + " \n", |
| 19 | + "- **最速手法**: \n", |
| 20 | + " - 右から左への単一ループ(O(n))\n", |
| 21 | + " - 早期リターンで平均O(1)~O(n)\n", |
| 22 | + " - in-place変更で追加メモリ最小化\n", |
| 23 | + " \n", |
| 24 | + "- **メモリ最小化**: \n", |
| 25 | + " - 基本的にin-place操作でO(1)\n", |
| 26 | + " - 全桁9のケースのみO(n)の新規メモリ\n", |
| 27 | + " \n", |
| 28 | + "- **CPython最適化**: \n", |
| 29 | + " - リスト操作は全てC実装で高速\n", |
| 30 | + " - `range()`の逆順イテレーションは効率的\n", |
| 31 | + " - リスト結合は`[1] + digits`より`[1, *digits]`が推奨\n", |
| 32 | + "\n", |
| 33 | + "### 業務開発視点\n", |
| 34 | + "\n", |
| 35 | + "- **型安全設計**: \n", |
| 36 | + " - `List[int]`での厳密な型ヒント\n", |
| 37 | + " - pylance完全対応の型アノテーション\n", |
| 38 | + " - Optional型での明示的なNone処理\n", |
| 39 | + " \n", |
| 40 | + "- **エラーハンドリング**: \n", |
| 41 | + " - 入力検証(空配列、型チェック、範囲チェック)\n", |
| 42 | + " - ValueError/TypeErrorの適切な使い分け\n", |
| 43 | + " - docstringでの例外明記\n", |
| 44 | + " \n", |
| 45 | + "- **可読性**: \n", |
| 46 | + " - 筆算アルゴリズムの直感的な実装\n", |
| 47 | + " - 変数名の明確化(carry, digit等)\n", |
| 48 | + " - 適切なコメント配置\n", |
| 49 | + "\n", |
| 50 | + "### Python特有分析\n", |
| 51 | + "\n", |
| 52 | + "- **データ構造選択**: \n", |
| 53 | + " - リスト操作が中心 → `list`が最適\n", |
| 54 | + " - 両端操作は少ない → `deque`不要\n", |
| 55 | + " - 順序保持必須 → `set`は不適\n", |
| 56 | + " \n", |
| 57 | + "- **標準ライブラリ活用度**: \n", |
| 58 | + " - この問題では標準ライブラリ不要(シンプルなリスト操作のみ)\n", |
| 59 | + " - `collections`、`itertools`等は過剰\n", |
| 60 | + " \n", |
| 61 | + "- **CPython最適化度**: \n", |
| 62 | + " - リスト走査は組み込みイテレータで高速\n", |
| 63 | + " - リスト結合はスライシングよりスプレッド演算子\n", |
| 64 | + " - インデックスアクセスはC実装で高速\n", |
| 65 | + "\n", |
| 66 | + "## 2. アルゴリズム比較表\n", |
| 67 | + "\n", |
| 68 | + "|アプローチ|時間計算量|空間計算量|Python実装コスト|可読性|標準ライブラリ活用|CPython最適化|備考|\n", |
| 69 | + "|---------|---------|---------|---------------|------|----------------|------------|-----|\n", |
| 70 | + "|右から走査(in-place)|O(n)|O(1)*|低|★★★|不要|適|*最悪時O(n)|\n", |
| 71 | + "|右から走査(immutable)|O(n)|O(n)|低|★★☆|不要|適|常に新規配列生成|\n", |
| 72 | + "|文字列変換|O(n)|O(n)|中|★☆☆|str, int組み込み|不適|型変換コスト大|\n", |
| 73 | + "|再帰処理|O(n)|O(n)|高|★☆☆|不要|不適|スタック使用|\n", |
| 74 | + "|BigInt演算|O(n)|O(n)|低|★★☆|組み込みint|不適|配列長制限なし時のみ有効|\n", |
| 75 | + "\n", |
| 76 | + "## 3. 採用アルゴリズムと根拠\n", |
| 77 | + "\n", |
| 78 | + "### 選択理由\n", |
| 79 | + "\n", |
| 80 | + "**右から走査(in-place)方式**を採用\n", |
| 81 | + "\n", |
| 82 | + "1. **計算量優位性**: \n", |
| 83 | + " - 時間: O(n)で最適、平均的には早期リターンでより高速\n", |
| 84 | + " - 空間: ほぼO(1)、最悪ケース(all 9s)のみO(n)\n", |
| 85 | + "\n", |
| 86 | + "2. **実装効率**: \n", |
| 87 | + " - Pythonのリスト操作は直感的\n", |
| 88 | + " - 標準的な筆算アルゴリズムで理解容易\n", |
| 89 | + " - コード量が少なく保守性高い\n", |
| 90 | + "\n", |
| 91 | + "3. **保守性**: \n", |
| 92 | + " - エッジケースが明確\n", |
| 93 | + " - デバッグが容易\n", |
| 94 | + " - チーム開発でも理解しやすい\n", |
| 95 | + "\n", |
| 96 | + "4. **Python特性**: \n", |
| 97 | + " - リスト操作はすべてC実装で高速\n", |
| 98 | + " - 型アノテーションが自然\n", |
| 99 | + " - pylanceとの相性良好\n", |
| 100 | + "\n", |
| 101 | + "### Python最適化戦略\n", |
| 102 | + "\n", |
| 103 | + "1. **逆順イテレーション**: `range(len(digits)-1, -1, -1)`でC実装の高速イテレータ活用\n", |
| 104 | + "2. **早期リターン**: 繰り上がり不要時に即座に処理終了\n", |
| 105 | + "3. **スプレッド演算子**: `[1, *digits]`で効率的なリスト結合\n", |
| 106 | + "4. **in-place変更**: LeetCode形式では許容され、メモリ効率的\n", |
| 107 | + "\n", |
| 108 | + "### トレードオフ\n", |
| 109 | + "\n", |
| 110 | + "- **可読性 vs パフォーマンス**: in-place変更は可読性を損なわないため両立\n", |
| 111 | + "- **型安全性 vs 簡潔性**: 型ヒントを付けても簡潔性は維持\n", |
| 112 | + "- **エラーハンドリング vs 速度**: 競プ版ではエラーチェック省略で高速化\n", |
| 113 | + "\n", |
| 114 | + "## 4. 実装パターン\n", |
| 115 | + "\n", |
| 116 | + "### 業務開発版(型安全・エラーハンドリング重視)\n", |
| 117 | + "Analyze Complexity\n", |
| 118 | + "Runtime 0 ms\n", |
| 119 | + "Beats 100.00%\n", |
| 120 | + "Memory 19.20 MB\n", |
| 121 | + "Beats 19.41%\n", |
| 122 | + "```python\n", |
| 123 | + "from typing import List\n", |
| 124 | + "\n", |
| 125 | + "class Solution:\n", |
| 126 | + " \"\"\"\n", |
| 127 | + " Plus One 問題の解決クラス\n", |
| 128 | + " \n", |
| 129 | + " 大きな整数を表す配列に1を加算する処理を提供\n", |
| 130 | + " \"\"\"\n", |
| 131 | + " \n", |
| 132 | + " def plusOne(self, digits: List[int]) -> List[int]:\n", |
| 133 | + " \"\"\"\n", |
| 134 | + " 整数配列に1を加算する(業務開発版)\n", |
| 135 | + " \n", |
| 136 | + " Args:\n", |
| 137 | + " digits: 各桁を表す整数リスト(最上位桁が先頭)\n", |
| 138 | + " 各要素は0-9の範囲内である必要がある\n", |
| 139 | + " \n", |
| 140 | + " Returns:\n", |
| 141 | + " 1を加算した結果の整数配列\n", |
| 142 | + " \n", |
| 143 | + " Raises:\n", |
| 144 | + " TypeError: 入力が配列でない、または要素が整数でない場合\n", |
| 145 | + " ValueError: 配列が空、または要素が0-9の範囲外の場合\n", |
| 146 | + " \n", |
| 147 | + " Examples:\n", |
| 148 | + " >>> Solution().plusOne([1, 2, 3])\n", |
| 149 | + " [1, 2, 4]\n", |
| 150 | + " >>> Solution().plusOne([9, 9, 9])\n", |
| 151 | + " [1, 0, 0, 0]\n", |
| 152 | + " \n", |
| 153 | + " Time Complexity: O(n) where n = len(digits)\n", |
| 154 | + " Space Complexity: O(1) 平均、O(n) 最悪時(all 9s)\n", |
| 155 | + " \"\"\"\n", |
| 156 | + " # 入力検証\n", |
| 157 | + " self._validate_input(digits)\n", |
| 158 | + " \n", |
| 159 | + " # 右から左へ走査\n", |
| 160 | + " for i in range(len(digits) - 1, -1, -1):\n", |
| 161 | + " # 現在の桁が9未満の場合\n", |
| 162 | + " if digits[i] < 9:\n", |
| 163 | + " digits[i] += 1\n", |
| 164 | + " return digits # 繰り上がり不要、即座に返却\n", |
| 165 | + " \n", |
| 166 | + " # 現在の桁が9の場合、0にして繰り上がり継続\n", |
| 167 | + " digits[i] = 0\n", |
| 168 | + " \n", |
| 169 | + " # 全桁が9だった場合(例: [9,9,9] → [1,0,0,0])\n", |
| 170 | + " return [1, *digits]\n", |
| 171 | + " \n", |
| 172 | + " def _validate_input(self, digits: List[int]) -> None:\n", |
| 173 | + " \"\"\"\n", |
| 174 | + " 入力配列の検証\n", |
| 175 | + " \n", |
| 176 | + " Args:\n", |
| 177 | + " digits: 検証対象の配列\n", |
| 178 | + " \n", |
| 179 | + " Raises:\n", |
| 180 | + " TypeError: 型が不正な場合\n", |
| 181 | + " ValueError: 値が制約を満たさない場合\n", |
| 182 | + " \"\"\"\n", |
| 183 | + " if not isinstance(digits, list):\n", |
| 184 | + " raise TypeError(\"Input must be a list\")\n", |
| 185 | + " \n", |
| 186 | + " if not digits:\n", |
| 187 | + " raise ValueError(\"Input list cannot be empty\")\n", |
| 188 | + " \n", |
| 189 | + " if len(digits) > 100:\n", |
| 190 | + " raise ValueError(\"Input size exceeds constraint (max 100)\")\n", |
| 191 | + " \n", |
| 192 | + " for i, digit in enumerate(digits):\n", |
| 193 | + " if not isinstance(digit, int):\n", |
| 194 | + " raise TypeError(f\"Element at index {i} must be an integer\")\n", |
| 195 | + " \n", |
| 196 | + " if not 0 <= digit <= 9:\n", |
| 197 | + " raise ValueError(\n", |
| 198 | + " f\"Element at index {i} ({digit}) must be in range [0, 9]\"\n", |
| 199 | + " )\n", |
| 200 | + " \n", |
| 201 | + " # 先頭が0でないことを確認(制約より)\n", |
| 202 | + " if len(digits) > 1 and digits[0] == 0:\n", |
| 203 | + " raise ValueError(\"Leading zero is not allowed\")\n", |
| 204 | + "```\n", |
| 205 | + "\n", |
| 206 | + "### 競技プログラミング版(パフォーマンス最優先)\n", |
| 207 | + "Analyze Complexity\n", |
| 208 | + "Runtime 0 ms\n", |
| 209 | + "Beats 100.00%\n", |
| 210 | + "Memory 19.25 MB\n", |
| 211 | + "Beats 17.57%\n", |
| 212 | + "```python\n", |
| 213 | + "from typing import List\n", |
| 214 | + "\n", |
| 215 | + "class Solution:\n", |
| 216 | + " def plusOne(self, digits: List[int]) -> List[int]:\n", |
| 217 | + " \"\"\"\n", |
| 218 | + " 整数配列に1を加算する(競プ最適化版)\n", |
| 219 | + " \n", |
| 220 | + " エラーハンドリング省略、性能最優先\n", |
| 221 | + " \n", |
| 222 | + " Time Complexity: O(n)\n", |
| 223 | + " Space Complexity: O(1) 平均、O(n) 最悪時\n", |
| 224 | + " \"\"\"\n", |
| 225 | + " # 右から左へ走査(インデックス逆順)\n", |
| 226 | + " for i in range(len(digits) - 1, -1, -1):\n", |
| 227 | + " if digits[i] < 9:\n", |
| 228 | + " digits[i] += 1\n", |
| 229 | + " return digits\n", |
| 230 | + " digits[i] = 0\n", |
| 231 | + " \n", |
| 232 | + " # 全桁が9の場合\n", |
| 233 | + " return [1, *digits]\n", |
| 234 | + "```\n", |
| 235 | + "\n", |
| 236 | + "### LeetCode提出用(最終版)\n", |
| 237 | + "\n", |
| 238 | + "```python\n", |
| 239 | + "class Solution:\n", |
| 240 | + " def plusOne(self, digits: list[int]) -> list[int]:\n", |
| 241 | + " \"\"\"\n", |
| 242 | + " Time Complexity: O(n)\n", |
| 243 | + " Space Complexity: O(1) average, O(n) worst case\n", |
| 244 | + " \"\"\"\n", |
| 245 | + " for i in range(len(digits) - 1, -1, -1):\n", |
| 246 | + " if digits[i] < 9:\n", |
| 247 | + " digits[i] += 1\n", |
| 248 | + " return digits\n", |
| 249 | + " digits[i] = 0\n", |
| 250 | + " \n", |
| 251 | + " return [1, *digits]\n", |
| 252 | + "```\n", |
| 253 | + "\n", |
| 254 | + "## 5. Python特有の最適化ポイント\n", |
| 255 | + "\n", |
| 256 | + "### CPython インタープリター最適化\n", |
| 257 | + "\n", |
| 258 | + "1. **組み込みイテレータ活用**\n", |
| 259 | + " ```python\n", |
| 260 | + " # range()の逆順イテレーションはC実装で高速\n", |
| 261 | + " for i in range(len(digits) - 1, -1, -1):\n", |
| 262 | + " ```\n", |
| 263 | + "\n", |
| 264 | + "2. **リスト操作最適化**\n", |
| 265 | + " ```python\n", |
| 266 | + " # スプレッド演算子によるリスト結合(Python 3.5+)\n", |
| 267 | + " return [1, *digits] # [1] + digits より効率的\n", |
| 268 | + " ```\n", |
| 269 | + "\n", |
| 270 | + "3. **早期リターン**\n", |
| 271 | + " ```python\n", |
| 272 | + " # 不要なループを回避\n", |
| 273 | + " if digits[i] < 9:\n", |
| 274 | + " digits[i] += 1\n", |
| 275 | + " return digits # 即座に終了\n", |
| 276 | + " ```\n", |
| 277 | + "\n", |
| 278 | + "### データ構造選択の根拠\n", |
| 279 | + "\n", |
| 280 | + "- **`list`を選択**: \n", |
| 281 | + " - インデックスアクセスO(1)\n", |
| 282 | + " - 末尾追加O(1)\n", |
| 283 | + " - CPythonでC実装、高速\n", |
| 284 | + " \n", |
| 285 | + "- **`deque`不要**: \n", |
| 286 | + " - 先頭挿入は最悪ケースのみ(稀)\n", |
| 287 | + " - この問題では`list`で十分\n", |
| 288 | + "\n", |
| 289 | + "### メモリ最適化\n", |
| 290 | + "\n", |
| 291 | + "1. **in-place変更**: \n", |
| 292 | + " - 新規メモリ確保を最小化\n", |
| 293 | + " - LeetCode形式では許容される\n", |
| 294 | + " \n", |
| 295 | + "2. **スプレッド演算子**: \n", |
| 296 | + " - `[1] + digits`はコピーが2回発生\n", |
| 297 | + " - `[1, *digits]`は1回で効率的\n", |
| 298 | + "\n", |
| 299 | + "## 6. 実装の特徴と利点\n", |
| 300 | + "\n", |
| 301 | + "### 型安全性(pylance対応)\n", |
| 302 | + "\n", |
| 303 | + "```python\n", |
| 304 | + "# Python 3.9+の型ヒント\n", |
| 305 | + "def plusOne(self, digits: list[int]) -> list[int]:\n", |
| 306 | + " # pylanceで完全な型チェックが可能\n", |
| 307 | + " # List[int]より list[int] が推奨(PEP 585)\n", |
| 308 | + "```\n", |
| 309 | + "\n", |
| 310 | + "### エッジケース処理\n", |
| 311 | + "\n", |
| 312 | + "```python\n", |
| 313 | + "# テスト例(実装には含めない)\n", |
| 314 | + "# [1,2,3] → [1,2,4] 早期リターン\n", |
| 315 | + "# [9] → [1,0] 単一要素、全桁9\n", |
| 316 | + "# [1,9,9] → [2,0,0] 部分的繰り上がり\n", |
| 317 | + "# [9,9,9] → [1,0,0,0] 全桁9、新規配列生成\n", |
| 318 | + "```\n", |
| 319 | + "\n", |
| 320 | + "### パフォーマンス特性\n", |
| 321 | + "\n", |
| 322 | + "- **平均ケース**: O(1)~O(k) (kは繰り上がり回数)\n", |
| 323 | + "- **最悪ケース**: O(n) (全桁が9)\n", |
| 324 | + "- **メモリ**: ほぼO(1)、最悪時のみO(n)\n", |
| 325 | + "\n", |
| 326 | + "この実装は、Pythonの特性を最大限活用し、可読性とパフォーマンスを両立した最適解となっています。" |
| 327 | + ] |
| 328 | + }, |
| 329 | + { |
| 330 | + "cell_type": "markdown", |
| 331 | + "id": "d91e2cb0", |
| 332 | + "metadata": {}, |
| 333 | + "source": [] |
| 334 | + } |
| 335 | + ], |
| 336 | + "metadata": { |
| 337 | + "language_info": { |
| 338 | + "name": "python" |
| 339 | + } |
| 340 | + }, |
| 341 | + "nbformat": 4, |
| 342 | + "nbformat_minor": 5 |
| 343 | +} |
0 commit comments