LeetCode算法45:跳跃游戏 II

问题
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。

示例:
输入: [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
说明:
假设你总是可以到达数组的最后一个位置。

思考
该题思路比较怪异,很难想到,不过可以作为知识储备,记下这种求解方式。以后遇到类似问题可以算是提供一个思路。

看示例:
[2,3,1,1,4]
我们从后往前推,最终目的是要跳到最后一个位置,即4的位置。但是这里的数字并没有意义。
对于第4个数1,需要跳一次;
对于第3个数1,显然只能跳到第4个数上,那么从第3个数开始跳到最后需要两次;
对于第2个数3,显然一步到位,跳一次;
对于第一个数2,只能选择跳一次还是跳两次,显然选择跳一次的收益更大,最终只需跳两次;

倒推时发现满足
①最优子结构,②重叠子问题。可以使用动态规划。

状态描述:f[i]表示在第i个位置最小需要几次可跳到最后一个位置
状态转移方程:f[i] = min(f[i+1]~f[i+nums[i]])+1
初始条件f[nums.length()-1]=0

对状态转移方程的说明:
在第i个位置上的数据,通过1步可以跳到下一个位置f(i+1)上,但是同时其具有选择跳nums[i]的机会,所以这里的最小值,是遍历其后1~nums个数量上的最小值,谁最小,就跳到哪个上面。

代码

class Solution {
    public int jump(int[] nums) {
        int f[] = new int[nums.length];
        if (nums.length == 0) {
            return 0;
        }
        if (nums.length == 1) {
            return 0;
        }
        f[nums.length - 1] = 0;
        for (int i = nums.length - 2; i >= 0; i--) {
            f[i] = findMin(f, i, nums[i]) + 1;
            if (f[i] < 0) f[i] = Integer.MAX_VALUE;
        }

        return f[0];

    }

    private int findMin(int[] f, int i, int num) {
        int min = Integer.MAX_VALUE;
        for (int j = 1; j <= num && i + j < f.length; j++) {
            min = Math.min(min, f[i + j]);//此处是查看从此处向后可以选择的值的范围,查找到最小值。本步骤的+1次跳跃在前面循环中增加;
        }
        return min;
    }
}

参考:
https://www.cnblogs.com/acbingo/p/9350223.html

猜你喜欢

转载自blog.csdn.net/xihuanyuye/article/details/100018004