右から左への繰り上がり処理による O(n) 実装
大きな整数を配列形式で表現したとき(各要素が1桁、最上位桁が先頭)、この整数に1を加算した結果を配列で返す問題です。
入力: digits = [1,2,3]
出力: [1,2,4]
説明: 123 + 1 = 124
入力: digits = [9,9,9]
出力: [1,0,0,0]
説明: 999 + 1 = 1000
入力: digits = [9]
出力: [1,0]
説明: 9 + 1 = 10
1 <= digits.length <= 100
0 <= digits[i] <= 9
[0,1,2] は不正)
O(n)
平均的には早期リターンでO(1)~O(k)
O(1) 平均
最悪時(全桁9)のみO(n)
class Solution:
def plusOne(self, digits: list[int]) -> list[int]:
"""
整数配列に1を加算する
Time Complexity: O(n)
Space Complexity: O(1) average, O(n) worst case
"""
# 右から左へ走査
for i in range(len(digits) - 1, -1, -1):
# 現在の桁が9未満の場合
if digits[i] < 9:
digits[i] += 1
return digits # 繰り上がり不要、即座に返却
# 現在の桁が9の場合、0にして繰り上がり継続
digits[i] = 0
# 全桁が9だった場合(例: [9,9,9] -> [1,0,0,0])
# 先頭に1を追加
return [1, *digits]
function plusOne(digits: number[]): number[] {
/**
* 整数配列に1を加算する
*
* Time Complexity: O(n)
* Space Complexity: O(1) average, O(n) worst case
*/
// 右から左へ走査
for (let i = digits.length - 1; i >= 0; i--) {
// 現在の桁が9未満の場合
if (digits[i] < 9) {
digits[i]++;
return digits; // 繰り上がり不要、即座に返却
}
// 現在の桁が9の場合、0にして繰り上がり継続
digits[i] = 0;
}
// 全桁が9だった場合(例: [9,9,9] -> [1,0,0,0])
// 先頭に1を追加
return [1, ...digits];
}
フローの説明:
1. 右端のインデックス(i = len-1)から開始
2. i >= 0 の間ループを継続
3. digits[i] < 9 なら +1 して即座に終了(成功パス・緑)
4. digits[i] == 9 なら 0 に設定し、i を減らして次の桁へ(繰り上がり継続・紫)
5. ループを抜けた = 全桁が9 → 先頭に1を追加して終了(特殊ケースパス・赤)
| ケース | 時間計算量 | 空間計算量 | 備考 |
|---|---|---|---|
| 最良ケース |
O(1)
|
O(1)
|
右端の桁が9未満、1回で終了 |
| 平均ケース |
O(k)
|
O(1)
|
k個の連続する9を処理(k < n) |
| 最悪ケース |
O(n)
|
O(n)
|
全桁が9、新配列生成が必要 |
| アプローチ | 時間 | 空間 | 実装コスト | 備考 |
|---|---|---|---|---|
| ✓ 右から走査(本実装) |
O(n)
|
O(1)平均
|
低 | 早期終了で高速、メモリ効率的 |
| 文字列変換 |
O(n)
|
O(n)
|
低 | 型変換オーバーヘッド大 |
| 完全immutable |
O(n)
|
O(n)
|
中 | 常に新配列生成、メモリ非効率 |
[1, *digits]
で効率的なリスト結合(全桁9のケースのみ)