前端算法第一三三弹-跳跃游戏 II

83 阅读1分钟

「这是我参与2022首次更文挑战的第40天,活动详情查看:2022首次更文挑战

给你一个非负整数数组 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

这道题是典型的贪心算法,通过局部最优解得到全局最优解。以下两种方法都是使用贪心算法实现,只是贪心的策略不同。

反向查找出发位置

我们的目标是到达数组的最后一个位置,因此我们可以考虑最后一步跳跃前所在的位置,该位置通过跳跃能够到达最后一个位置。

如果有多个位置通过跳跃都能够到达最后一个位置,那么我们应该如何进行选择呢?直观上来看,我们可以「贪心」地选择距离最后一个位置最远的那个位置,也就是对应下标最小的那个位置。因此,我们可以从左到右遍历数组,选择第一个满足要求的位置。

找到最后一步跳跃前所在的位置之后,我们继续贪心地寻找倒数第二步跳跃前所在的位置,以此类推,直到找到数组的开始位置。


/**
 * @param {number[]} nums
 * @return {number}
 */
var jump = function(nums) {
    // 必须到达end下标的数字
    let end = nums.length - 1;
    let length = 0;

    while (end > 0) {
        // 最远到这个下标的前下标
        let max = -1;

        for (let j = end - 1; j >= 0; j--) {
            if (end - j <= nums[j]) {
                max = j;
            }
        }

        if (max == -1) {
            return 0;
        }

        end = max;
        length += 1;
    }

    return length;
};