Skip to content

Commit e22ef0a

Browse files
authored
Merge pull request #241 from myoshi2891/dev-from-macmini
feat: add solution and documentation for LeetCode 66. Plus One
2 parents d149f73 + 1e07b3f commit e22ef0a

4 files changed

Lines changed: 2531 additions & 0 deletions

File tree

Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
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

Comments
 (0)