Jump Game II

来源:互联网 发布:pp手机助手 mac 编辑:程序博客网 时间:2024/05/21 17:44

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。