LeetCode | Jump Game

100 篇文章 0 订阅
4 篇文章 0 订阅

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.

Determine if you are able to reach the last index.

For example:
A = [2,3,1,1,4], return true.

A = [3,2,1,0,4], return false.

讲道理这道题的贪心性质并不是特别明显,而我一开始写的也很拖沓
后来仔细看了一下第一次提交的虽然wa了但是过了69/72的用例,是所有提交中通过最多的,囧o(╯□╰)o

    int step=0;
    //当没有走到最后一格的时候
    while(step<n-1){
        int max=step;
        //从当前位置出发,走哪一步呢?
        //走i+nums[i]最大的那个,因为那个位置可以走到最远
        for(int i=step;i<=step+nums[step];i++){
            if(i+nums[i]>max)
            max=i;
        }
        //如果那个可以走到最远的位置和当前相同,说明走不了
        if(max==step) return false;
        //走到这个最远点
        step=max;
    }
    return true;

//于是改了改代码,如下,虽然过了71/72个用例,但是发现这种贪心策略其实是错误的

if(i+nums[i]>max)
max=i+nums[i];

这种贪心策略是一次可以走到目的地点能扩展到的最远点。
最后一个用例过不去说明了这个策略的错误性
[5,9,3,2,1,0,2,3,3,1,0,0]
如果按照之前的策略,路线为5->9->0 且未到达最远点,false
但是实际上可以走5->9->3->0 到达,true

于是策略应当改变为走到目的地点能扩展到最远点的,目的点。
好拗口,也就是之前是走到i+nums[i],但是现在仅仅是走到i了。

不过这个会产生很多问题,比如最后一步可以到达却走不到。
[2,5,0,0]
这种情况其实要求我们在继续进入循环之前,判断step+nums[step]可否走到终点。

int step=0,pos;
        do{
            int max=step,i=step;
            pos=step;
            for(;i<=step+nums[step];i++){
                if(i+nums[i]>max){
                    max=i+nums[i];
                    pos=i;
                }
            }
            //无法到达或者扩展到终点
            if(pos==step && pos+nums[pos]<n-1) return false;
            step=pos;
            //可以扩展到终点
            if(step+nums[step]>=n-1) break;
        }while(step<n-1);
        return true;

虽然代码写的很挫,但是终归是把自己的思路实现了。

然后经看题解之后,发现他使用的是一种非常巧妙的办法:
仅仅4行代码…

int reach=0;
for(int i=0;i<=reach && reach<n;i++){
    reach=max(reach,i+nums[i]);
}
return reach>=n-1;

嗯,记录是最远能到达什么地方,如果经过当前的位置可以达到更远的地方,则更新。

这个很值得记忆~~

另外,此题还有DP的解法:
状态是第i位的时候可以留下的最多的步数,然后这一步数会由之前的积累或者上一步决定。
按照惯例,我们使用数组推;
描述1
可以得出dp[i]=max{dp[i-1],nums[i-1]}-1;
于是DP很容易就可以写出来

    vector<int> dp(n,0);
    dp[0]=nums[0];
    for(int i=1;i<n;i++){
        dp[i]=max(dp[i-1],nums[i-1])-1;
    }
    return dp[n-1]>=0;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值