跳跃游戏||贪心算法

给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]

每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处:

  • 0 <= j <= nums[i] 
  • i + j < n

返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]

#include <iostream>
#include <vector>
using namespace std;

class Solution {
public:
    int jump(vector<int>& nums) {
        int n = nums.size();
        if (n <= 1) return 0; // 如果数组长度小于等于1,不需要跳跃

        int jumps = 0;            // 跳跃次数
        int current_end = 0;     // 当前能到达的最远位置
        int farthest = 0;         // 记录能达到的最远位置

        for (int i = 0; i < n - 1; ++i) { // 只需遍历到倒数第二个元素
            farthest = max(farthest, i + nums[i]); // 更新最远位置
            if (i == current_end) { // 当到达当前可跳跃的边界时
                jumps++; // 需要跳跃
                current_end = farthest; // 更新可跳跃的边界
                if (current_end >= n - 1) break; // 如果已到达或超出最后一个位置,结束
            }
        }

        return jumps; // 返回跳跃次数
    }
};

int main() {
    Solution sol;
    vector<int> nums = {2, 3, 1, 1, 4}; // 示例输入
    cout << "最小跳跃次数: " << sol.jump(nums) << endl; // 输出结果
    return 0;
}

代码解释

  1. 特殊情况处理

    • 如果数组长度小于或等于1,直接返回0,因为不需要跳跃。
  2. 循环遍历

    • for 循环遍历数组,直到倒数第二个元素(因为最后一个元素不需要跳跃到达)。
    • 在循环中,更新 farthest,表示当前索引能跳跃到的最远位置。
  3. 跳跃计数

    • 当当前索引 i 达到 current_end 时,增加跳跃计数 jumps,并更新 current_endfarthest
    • 如果在跳跃过程中更新 current_end 超过了数组的最后一个索引,提前结束循环。

复杂度分析

  • 时间复杂度:O(n),我们只需遍历一次数组。
  • 空间复杂度:O(1),只使用常数级的额外空间。

逻辑分析

1. 问题描述
  • 我们有一个数组 nums,数组中的每个元素表示从当前索引位置最多可以跳跃的距离。
  • 我们需要从数组的第一个元素开始,通过最少的跳跃次数,跳到最后一个元素。
2. 贪心策略

贪心的基本思想是:在每次跳跃时,选择能到达的最远位置。我们通过在每一步中选择当前能跳跃的最远位置,贪心地确保每次跳跃的步骤尽量大,从而减少跳跃次数。

3. 核心变量
  • jumps:记录跳跃的次数。
  • current_end:表示当前跳跃范围的终点。在到达 current_end 时,必须进行一次跳跃。
  • farthest:表示在当前跳跃范围内能到达的最远位置。每次更新时,通过 farthest = max(farthest, i + nums[i]) 来动态计算新的最远位置。
4. 贪心算法的执行逻辑
  1. 初始化

    • jumps = 0:表示还未跳跃。
    • current_end = 0:当前跳跃范围的终点为起始位置。
    • farthest = 0:当前能跳跃到的最远位置也是起始位置。
  2. 遍历数组

    • 遍历数组时,对于每个索引 i,更新最远可到达的位置 farthestfarthest = max(farthest, i + nums[i]),即在当前索引 i,计算从这个位置跳跃后,能到达的最远位置 i + nums[i]
  3. 跳跃判断

    • 如果 i 达到了 current_end(即跳跃的终点),说明在这之前的所有位置都已经处理过了,必须进行一次跳跃,并更新跳跃范围为 farthest。即:到达当前跳跃范围时,必须进行一次跳跃
    • 每次跳跃后,current_end 更新为 farthest,表示下一次跳跃时的范围边界。
  4. 提前结束

    • farthest 能够到达或超过数组的最后一个元素时,可以提前结束,因为我们已经找到了到达最后一个位置的路径。
5. 流程示例

假设数组为 nums = [2, 3, 1, 1, 4]

  • 初始状态

    • left = 0, right = n-1 (为了指代开头和结尾)。
    • current_end = 0, farthest = 0, jumps = 0
  • 第一步

    • 开始遍历:
      • i = 0,farthest = max(farthest, 0 + nums[0]) = max(0, 2) = 2
      • 到达 current_end 时,必须跳跃,跳跃次数 +1,current_end 更新为 farthest = 2
  • 第二步

    • 继续遍历:
      • i = 1,farthest = max(farthest, 1 + nums[1]) = max(2, 4) = 4
      • i = 2,farthest = max(farthest, 2 + nums[2]) = max(4, 3) = 4
      • 到达 current_end 时(即 i = 2),再次跳跃,跳跃次数 +1,current_end 更新为 farthest = 4
  • 结束

    • 因为此时 farthest = 4,已经可以到达数组的最后一个元素,结束跳跃,返回跳跃次数 2。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值