Jump Game II - LeetCode

Jump Game II - LeetCode

题目


大概翻译一下题目的意思,有一个非负整数数组,数组某个index上的数值代表在这个index上能跳的最大步数,要从这个数组的第一个位置跳到最后一个位置,求跳动的最少次数。
例:A = [2,3,1,1,4]
从A[0]开始跳,A[0]=2,所以在这个位置最多能跳2步。
如果跳两步那么就到了A[2],而A[2]=1所以在这个位置只能跳1步
显然这个样例的答案是2,在A[0]跳1步,到达A[1],再从A[1]跳3步到达数组最后一个位置


先写一下我的2B方法
题目要求最少的次数,显然可以用BFS做
具体的做法是用一个队列存储当前的位置,然后把从这个位置能到达的所有其他位置按顺序(按什么顺序视情况而定,后面会提到)压入队列,
另外再创建一个队列用来记录到达当前位置已用的步数

这样已经可以得到正确答案了,但是效率不高,所以提交的时候超时了,因为很多节点会被重复考虑,举个例子
比如B=[2,2,2,1,4],到达B[2](注意是B[2])有两种方法:
1.先跳1步,再跳1步,共跳2次
2.跳两步,共跳1次
显然这里只需要考虑第2种方法就行,因为不论用哪种方法,到达B[2]后,接下来的情况是相同的,而第一种方法已经跳了2次,最后的跳动次数一定会比第二种方法多。

所以要去掉这种重复冗余的情况,去掉的方法就是用一个set存储已经经过的节点,当再次到达该节点时就忽略。
为什么这样就能起作用?因为在做BFS的时候,某个index可能会被到达多次,但是第一次到达该index所用的跳动次数一定是最少的

优化之后过了91/92个测试,就差了1个。。
这时候就要考虑顺序了,,我一开始是按步数递增的顺序把下一个index压入队列的。这样做的结果是,每次都优先考虑了跳一步的情况,,所以会很慢,,,于是改了一下顺序,按步数递减的顺序把下一个index压入队列,这样就会优先考虑跳动步数最大的情况。

#include <iostream>
#include <vector>
#include <queue>
#include <set>
using namespace std;

class Solution {
public:
    int jump(vector<int>& nums) {
        int n = nums[0], p = 0, i = 0, steps = 0;
        set<int> s;
        queue<int> pos;
        queue<int> step;
        s.insert(0);
        pos.push(0);
        step.push(0);
        while (!pos.empty() && p < nums.size()-1) {
            p = pos.front(); pos.pop();
            steps = step.front(); step.pop();
            steps++;
            for (i = nums[p]; i >= 1; i--) {    //这里改动了顺序
                if (p + i == nums.size()-1) break;
                if (s.find(p+i) == s.end()) {
                    pos.push(p+i);
                    step.push(steps);
                    s.insert(p+i);
                }
            }
            if ((p + i == nums.size()-1) && (i != nums[p]+1)) break;
        }
        return steps;
    }

};

这里写图片描述

结果不是太好,看了别人的方法才知道可以把两个队列合并成1个队列,用pair就行。。这样就会少很多次pop,push操作

下面是效率最高的做法

class Solution {
public:
    int jump(vector<int>& nums) {
        int cnt = 0;
        int maxidx = 0;
        int curidx = 0;
        for(int i=0; i<nums.size()-1; i++){
            maxidx = max(maxidx, nums[i]+i);
            if(i==curidx){
                cnt++;
                curidx = maxidx;
            }
        }
        return cnt;
    }
};

代码很简洁,仔细去理解一下这个代码会发现其实这个方法有些投机的成分,为什么这么说?
题目里最后有个note说,“你可以认为你永远能够到达最后一个index”,大多数人会认为这个条件是题目的一个简化,可以让我们少考虑一些情况,但是这个解法重分利用了这个条件——“你总是能够到达最后一个index”。

这解法的思路是“尽可能地走往后走”,反正一定能到达最后一个index,那么只要尽可能往后走就一定能以最少的步数到达最后的index。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值