LeetCode | Jump Game II(跳跃游戏II)

本文探讨了如何在给定的非负整数数组中,从首个元素出发,以最少的跳跃次数抵达最后一个元素的问题。提供了三种解决方案:动态规划、改进的动态规划以及贪心算法,并对比了不同实现方式的时间效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Given an array of non-negative integers, you are initially positioned at the first index of the array.

Each element in the array represents your maximum jump length at that position.

Your goal is to reach the last index in the minimum number of jumps.

For example:
Given array A = [2,3,1,1,4]

The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then 3 steps to the last index.)


题目解析:

要跳转到最后一个位置,至少要跳多少次。


方案一:动态规划(大数据超时)

我们可以利用动态规划,第i个元素能跳A[i]步。那么其跳转到最后结点的次数至少是step[i+1]....step[i+a[i] ]最小值+1。

这样就需要设一个step[n]数组来保存要至少跳转多少步,最后返回step[0]即可。

class Solution {
public:
    int jump(int A[], int n) {
        if(n <= 1)
            return 0;
        int *step = new int[n];
        step[n-1] = 0;
        for(int i = n-2;i >= 0;i--){
            if(A[i] + i >= n-1){
                step[i] = 1;
            }else{
                int min = step[i+1];
                for(int j = 2;j <= A[i];j++){
                    if(min > step[i+j])
                        min = step[i+j];
                }
                step[i] = min + 1;
            }
        }
        return step[0];
    }
};

令人诧异的是,为什么有个网友写的动态规划却没超时?虽然时间复杂度O(n^2),但我的明显效率更高一些,我们有把i...n-1的全遍历。现在贴出来看看,有网友知道的话,麻烦告知一下。

class Solution {
public:
    int* dp;
    int jump(int A[], int n) {
        if(n==0)
        {
            return INT_MAX;
        }
        dp = new int[n];
        dp[0] = 0;
        for(int i=1;i<n;i++)
        {
            dp[i] = INT_MAX;
        }
        for(int i=1;i<n;i++)
        {
            for(int j=0;j<i;j++)
            {
                if(j+A[j]>=i)
                {
                    int tmp = dp[j]+1;
                    if(tmp < dp[i])
                    {
                        dp[i] = tmp;
                        break;
                    }
                }
            }
        }
        
        return dp[n-1];
    }
};



方案二:

借助LeetCode | Jump Game方案二的思想。

当从前向后遍历的时候,不断更新最大值,当最大值大于n的时候就能保证跳转成功。那么我们如何借鉴呢?

我们用range来保存从第i点开始能跳转到第几个结点,那么在i....range范围内,我们只计算a[j]+j,来更新内部的一个max,表示这个范围内的数据能跳转到的最远索引值。只有在range...max中遍历时,才更新count。当max>=n时,证明从i...range中至少有一个位置j,可以一次跳转到终点。

class Solution {
public:
    int jump(int A[], int n) {
        if(n<=1)
            return 0;

        int count = 0;
        int range = A[0];
        for(int i = 0;i < n;){  //这里不能再i++,因为子过程中的while循环的i++已经达到了下次要循环的边界
            count++;
            if(range >= n-1)
                return count;
            //找到下次循环的最大位置
            int max = 0;
            while(i <= range){
                max = max > A[i]+i ? max : A[i]+i;
                i++;
            }
            range = max;
        }
        return count;
    }
};


同样的思路,网友的代码更好一些,但要仔细揣摩才能出来。

class Solution {
public:
    int jump(int A[], int n) {
       int jump = 0;
       int lastMax = 0;    //trace the max with jump times jump
       int curMax = 0;    //trace the max from 0~i

       for(int i = 0; i < n; i ++)
       {
           if(lastMax < i)
           {
                jump ++;            // need a jump!
                lastMax = curMax;    // jump to new max(curMax)
           }
           curMax = max(curMax, A[i]+i);
       }
       return jump;
    }
};




方案三:贪心算法

更精巧的方法,不过时间复杂度有点高,但思想很不错!先找到第一个能一口气跳到最后的,然后找哪一个能一口气跳转到该位置的,以此类推。

class Solution{
public:
    int jump(int A[], int n) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        int count = 0;
        int end = n-1;
        while(end){
            for(int i = 0; i < end; i++){
                if((A[i]+i)>=end){
                    count++;
                    end = i;
                }
            }
        }
        return count;
    }
    
};






















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值