力扣 leetcode 45. 跳跃游戏 II

问题描述

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

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

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

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

提示:

  • 1 <= nums.length <= 10^4
  • 0 <= nums[i] <= 1000

示例

示例 1:

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

示例 2:

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

解题思路

这里我们可以从起始位置出发,根据当前可跳跃次数,来更新后面位置的最少跳跃次数。如果后面某个位置 j 是由当前位置 i 跳跃过去的,即当前位置最少需要跳跃 x 次,则判断 x+1 是否小于 i 的最小跳跃次数,如果小于,则更新它的值。

但是这样做存在大量重复遍历的节点,例如 nums=[5,1,1,1,1,1,1] ,在这里,我们从 0 开始跳跃两步即可抵达终点,按我们之前的方法却要遍历多 1, 2, 3, 4 这四个位置。因此,我们可以记录一下上一轮最远的跳跃位置,如果当前位置跳跃无法跳出上一轮的最远位置,就不需要再考虑这个位置了(因为跳跃次数一定比上一次的跳跃次数多)。

同时,在这种情况下,我们发现,每次更新最少跳跃次数,更新值都不超过上一次的更新值。这对我们有两个帮助:1,只要我们从某个点出发,最远跳跃位置达到了末尾,则可以终止判断了,已经找出了最少跳跃次数;2,每次更新最少跳跃次数时,我们无需与上一次保存的值进行比较。

最终的代码如下:

class Solution {
public:
    int jump(vector<int>& nums) {
        vector<int> dp(nums.size(), 0x7ffffff);
        int tmp;
        int pre_max = 0;
        int max = 0;
        int max_idx = nums.size() - 1;
        dp[0] = 0;
        for(int i = 0; i < nums.size(); i++){
            if(i + nums[i] < max){
                continue;
            }
            else{
                pre_max = max;
                max = (i + nums[i]) < nums.size() ? (i + nums[i]) : (max_idx) ;
            }
            if(pre_max == max_idx){
                break;
            }
            tmp = dp[i] + 1;
            for(int j = pre_max + 1; j <= max; j++){
                dp[j] = tmp;
            }
        }
        return dp[max_idx];
    }
};
posted @ 2022-11-29 20:49  greatestchen  阅读(27)  评论(0编辑  收藏  举报