🚀 Jump Game Algorithm Analysis

配列の最後のインデックスに到達できるかを判定するアルゴリズムの詳細解析

💻 TypeScript実装

/**
 * 配列の最後のインデックスに到達できるかどうかを判定する関数
 * 
 * @param nums - 各位置での最大ジャンプ長を表す整数配列
 * @returns 最後のインデックスに到達できる場合はtrue、そうでなければfalse
 * 
 * 時間計算量: O(n) - 配列を一度だけ走査
 * 空間計算量: O(1) - 定数の追加メモリのみ使用
 */
function canJump(nums: number[]): boolean {
    // 現在到達可能な最大インデックスを追跡
    let maxReach: number = 0;
    
    // 配列の各要素を順番に処理
    for (let i: number = 0; i < nums.length; i++) {
        // 現在の位置が到達可能範囲を超えている場合、最後まで到達不可能
        if (i > maxReach) {
            return false;
        }
        
        // 現在の位置から到達可能な最大インデックスを更新
        maxReach = Math.max(maxReach, i + nums[i]);
        
        // 既に最後のインデックス以上に到達可能な場合、早期終了
        if (maxReach >= nums.length - 1) {
            return true;
        }
    }
    
    // ループが完了した場合、最後のインデックスに到達可能
    return true;
}

🔍 アルゴリズム解析

Step 1: 初期化

maxReachを0で初期化。これは現在到達可能な最大インデックスを追跡します。

初期状態: maxReach = 0

Step 2: 配列の走査

配列の各要素を順番に処理し、各位置で以下をチェック:

  • 現在位置が到達可能範囲内か
  • 現在位置から到達可能な最大距離の更新
  • 最終インデックスに到達可能かの早期判定

Step 3: 到達可能性判定

各位置で i > maxReach の場合、その位置には到達できないため即座にfalseを返します。

📊 Example 1: [2,3,1,1,4] の実行過程

🎯 Input: nums = [2,3,1,1,4] → Output: true

初期状態

0 2
1 3
2 1
3 1
4 4

i = 0: maxReach = 0, nums[0] = 2

計算: maxReach = max(0, 0 + 2) = 2

i = 1 の処理

0 2
1 3
2 1
3 1
4 4

i = 1: maxReach = 2, nums[1] = 3

計算: maxReach = max(2, 1 + 3) = 4

判定: maxReach (4) ≥ nums.length - 1 (4) → true を返す

📊 Example 2: [3,2,1,0,4] の実行過程

❌ Input: nums = [3,2,1,0,4] → Output: false

i = 0 の処理

0 3
1 2
2 1
3 0
4 4

i = 0: maxReach = max(0, 0 + 3) = 3

i = 1, 2, 3 の処理

0 3
1 2
2 1
3 0
4 4

i = 3: nums[3] = 0, maxReach = max(3, 3 + 0) = 3

重要: インデックス3から先に進めない(ジャンプ長が0)

i = 4 で: i (4) > maxReach (3) → false を返す

⚡ 計算量解析

🕒 時間計算量: O(n)

理由: 配列の各要素を最大1回だけ処理するため
最良の場合: O(1) - 最初の要素で最終インデックスに到達可能と判明
最悪の場合: O(n) - 全ての要素を処理する必要がある

💾 空間計算量: O(1)

理由: maxReach変数のみを使用し、入力サイズに関係なく一定
追加メモリ: 整数変数のみ(数バイト)

🔑 重要なポイント

1. 貪欲法(Greedy Algorithm)

各段階で最適な選択(最大到達距離の更新)を行い、全体的に最適解を得る手法です。

2. 早期終了による最適化

最終インデックスに到達可能と分かった時点で即座にtrueを返すことで、無駄な計算を回避します。

3. 単一パス処理

配列を一度だけ走査することで効率的な解法を実現しています。