45. 跳跃游戏 II

45. 跳跃游戏 II

题目链接:45. 跳跃游戏 II(中等)

给你一个非负整数数组 nums ,你最初位于数组的第一个位置。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

你的目标是使用最少的跳跃次数到达数组的最后一个位置。

假设你总是可以到达数组的最后一个位置。

示例 1:

输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
    从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。

示例 2:

输入: nums = [2,3,0,1,4]
输出: 2

提示:

  • 1 <= nums.length <= 104

  • 0 <= nums[i] <= 1000

解题思路

本题与55. 跳跃游戏 难一些,但不变的是从覆盖范围出发,不管怎么跳,覆盖范围内一定是可以跳到的

如下图所示,首先第一步的起点肯定是 nums[0]。从下图中,可以看到 nums[0] = 2,那么第一步能走到的最大距离在下标为 2 的位置。当走到下标2的位置时,还没有到达终点,需要走第二步,此时需要找出第二步能走的最大距离(为了找到第二步能走的最大距离,在走第一步时,就要记录下第二步能走的最大距离。那么在走第一步时,一定会经过下标[1,2],在下标1的位置处可以得到第二步能走的最大距离是小标为 4 的位置)。所以总的只需要走两步,即 0—>1—>4。

这道题依然使用的是贪心算法。局部最优:当前可移动距离尽可能多走,如果还没到终点,步数加一。整体最优:一步尽可能多走,从而达到最小步数。

这里有一点需要注意: 不访问数组的最后一个元素 ,因为在访问最后一个元素之前,最大覆盖范围一定能覆盖最后一个位置(题目表明一定能到达最后一个位置)。

C++

class Solution {
public:
    int jump(vector<int>& nums) {
        if (nums.size() == 1) return 0;
        int curMaxIndex = 0; // 当前这一步可以走的最大范围
        int nextMaxIndex = 0; // 用于记录在遍历 curCover 过程中可以遇到的 下一步的最大覆盖范围
        int minStep = 0; // 记录走的步数
        // 注意 i < nums.size() - 1,统一处理。即:移动下标只要遇到当前覆盖最远距离的下标,直接步数加一,不考虑是不是终点的情况。
        for (int i = 0; i < nums.size() - 1; i++) {
            if (nums[i] + i > nextMaxIndex) { // 更新下一步的最大覆盖范围
                nextMaxIndex = nums[i] + i;
            }
            if (i == curMaxIndex) { // 遇到 当前这一步能走的最远距离,说明即将开始下一步
                curMaxIndex = nextMaxIndex; 
                minStep++;
            }
        }
        return minStep;
    }
};

JavaScript

var jump = function(nums) {
    let curMaxIndex = 0;
    let nextMaxIndex = 0;
    let minSetup = 0;
    for (let i = 0; i < nums.length - 1; i++) {
        nextMaxIndex = Math.max(nextMaxIndex, nums[i] + i);
        if (curMaxIndex === i) {
            curMaxIndex = nextMaxIndex;
            minSetup++;
        }
    }
    return minSetup;
};

 

原文地址:https://www.cnblogs.com/wltree/p/15768326.html