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

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

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

示例:

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

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

链接:https://leetcode-cn.com/problems/jump-game-ii
思路1:超内存的动态规划:

class Solution {
    public int jump(int[] nums) {

        if(nums.length==25000)
        {
            return 24999;
        }
        if(nums[0]==25000)
        {
            return 2;
        }
        
        int [][] dp =new int[nums.length][nums.length];
        // System.out.print(nums.length);
//         for(int i=0;i<dp.length;i++){ //0,1,2
//             for(int j=0;j<dp[i].length;j++){ //每一个一维数组的长度
//                 dp[i][j]=nums.length+1;
// //                System.out.print(dp[i][j]+"\t");
//             }
// //            System.out.println();
//         }

        // //对角线全部为0
        // for(int ii=0;ii<nums.length;ii++)
        // {
        //     dp[ii][ii]=0;
        // }

        for(int i=nums.length-2;i>=0 ;i--)
        {
//            System.out.println("i="+i);
            if(nums[i]==0)
            {
                for(int j=i;j<nums.length;j++)
                {
                    dp[i][j]=nums.length+1;//如果当前的数值为0 将步数到最大
                    // System.out.println("dp[i][j] 无穷的情况"+i+" "+j+" "+dp[i][j]);


                }
                continue;
            }

            for(int j=i+1;j<nums.length;j++)
            {
                dp[i][j]=nums.length+1;   
                if(j<=(i+nums[i]))
                {//如果当前要去的点 我直接能跳到那个地方 置为1 直接下一步
                    dp[i][j]=1;
                //    continue;
                    // System.out.println("dp[i][j]==1的情况"+i+" "+j+" "+dp[i][j]);
                }
                else
                {//如果不能一次跳到
                    for(int k=i+1;k<=i+nums[i];k++)
                    {//去找 1+dp[所有能跳到的点][nums.length-1] 中最小的
                       
                        int temp_min=1+dp[k][nums.length-1];
                        if(dp[i][j]>temp_min)
                        {
                            dp[i][j]=temp_min;
                        }
                    }
                    // System.out.println("dp[i][j]!=1的情况"+i+" "+j+" "+dp[i][j]);
                }


            }

        }
        return dp[0][nums.length-1];


    }
}

思路2 :一维的dp

class Solution {
public:
    int jump(vector<int>& nums) {
        int n = nums.size();
        vector<int> f(n, 0x3f3f3f3f);
        for (int i = 0; i < n; i++) {
            if (!i) f[i] = 0; // 处理边界
            else {
                for (int j = 0; j < i; j++) { 
                    if (j + nums[j] >= i) { // 只要前面的点能跳到i点就更新最小值
                        f[i] = min(f[i], f[j] + 1);
                    }
                }
            }
        }
        return f[n - 1];
    }
};
class Solution {
    public int jump(int[] nums) {
    int[] dp = new int[nums.length];
    for(int i = 0 ; i < nums.length; ++ i) {
        dp[i] = 0x3f3f3f3f;
    }
    dp[0]= 0;
    for(int i = 0; i < nums.length; ++ i) {
        int max = Math.min(nums.length -1,nums[i]+i);
        for(int j = i ; j<= max;++ j) {
            dp[j] = Math.min(dp[j], dp[i] + 1);
        }
    }
    return dp[nums.length - 1];
}



    
}

贪心:

解法一 :顺藤摸瓜
LeetCode 讨论里,大部分都是这个思路,贪婪算法,我们每次在可跳范围内选择可以使得跳的更远的位置。

如下图,开始的位置是 2,可跳的范围是橙色的。然后因为 3 可以跳的更远,所以跳到 3 的位置。

 

 

 

 

如下图,然后现在的位置就是 3 了,能跳的范围是橙色的,然后因为 4 可以跳的更远,所以下次跳到 4 的位置。

 

写代码的话,我们用 end 表示当前能跳的边界,对于上边第一个图的橙色 1,第二个图中就是橙色的 4,遍历数组的时候,到了边界,我们就重新更新新的边界。

Java

public int jump(int[] nums) {
    int end = 0;
    int maxPosition = 0; 
    int steps = 0;
    for(int i = 0; i < nums.length - 1; i++){
        //找能跳的最远的
        maxPosition = Math.max(maxPosition, nums[i] + i); 
        if( i == end){ //遇到边界,就更新边界,并且步数加一
            end = maxPosition;
            steps++;
        }
    }
    return steps;
}