有一段直线距离,这段距离上分布着 n 个 格子
每个位置上都标有数字,表示可以从这个格子往前最多跳跃几格
最少跳几步,可以从起点跳到终点?
如上图就是需要从A点跳到C点
在A点,可以往前最多跳2格,也就是在A点 可以往前跳一格或者两格
B点就可以看成一个坑,像上图这个例子中,这个坑就是没办法逾越的,所以没办法跳到终点
这道题目被归类为贪心算法
贪心算法都有个贪心思想
既然我需要得到最少跳几步,那么我就死活不跳
到了不得不跳的时候,再挑一个跳的最远的位置,来跳
定义a为当前格子,b为当前格子能到的最远距离
像上面这个例子
把A点看成 a,把A点能跳到的最远距离看成 b(也就是第三个位置)
什么叫不得不跳?
A只能走一步或者两步,而我现在就在A点,那么就要考虑在(a,b] 这段距离内
哪个格子能够尽可能地跳的更远,而且一定要选一个格子跳
也就是每次来到一个新格子,就要考察(a,b] 那个格子能跳的更远
所以这里的贪心思想是:不得不跳我再跳,跳了我就选最大的跳
这里我们可能会思考这个“坑”怎么考虑,因为每次选最好的格子跳
最后如果最远只能跳到一个坑里,那自然就是没法越过这个坑,返回失败即可
这里我们的jumpGame2()方法返回的是最少需要跳几步
600是设置的跳到坑中的情况
int main(){
vector steps;
steps.push_back(1);
steps.push_back(1);
steps.push_back(3);
steps.push_back(2);
steps.push_back(1);
//steps.push_back(0); //注释这一行看这个坑有没有起效
steps.push_back(2);
steps.push_back(3);
steps.push_back(5);
steps.push_back(2);
Solution solve;
int result = solve.jumpGame2(steps);
if(result == 0)
printf("你只有一个格子或者一个格子都没有,跳0步!");
else if(result == 600)
printf("你不得不跳入一个坑中,结束一生!");
else
printf("总共需要跳跃%d步!",result);
}
current_index存放的是 当前这个格子 能到达的最远距离
pre_index存放的是 (a,b]之间的格子 能去往的最远距离
每次指针扫描到current_index+1的时候,也就是不得不做选择
在(a,b]之间选择一个能够跳的最远的格子进行跳远的时候
不得不跳,又只能跳到坑中,之间返回入坑(这里用自己设置的错误码600)
不是做选择的时候,就是挑选(a,b]之间最好的格子,等到不得不跳的时候,就选这个格子来跳
当然,这里还设置了一个小trick,当我在扫描(a,b]的时候
发现有个格子能直接到达或者超过终点,直接选这个节点就对了,也算是小小的贪心,后面的都不考虑了
为什么跳两步,就是跳过被选中的节点,再跳到终点,是两步
class Solution{
public:
int jumpGame2(vector steps){
//如果格子小于等于1,返回错误1,一步都不跳
if(steps.size() <= 1)
return 0;
//current_index = steps[a]+a;
int current_index = steps[0];
//pre_index = (a,b] 之间的能去到的最远距离
int pre_index = steps[0];
//跳跃次数
int times = 0;
//记录每次跳哪一步
int theBestChoise = 0;
for(int i = 1;i < steps.size();i++){
//指针来到 b+1的位置,不得不跳出一步
if(i > current_index){
current_index = pre_index;
//不得不走一步,只能走到一个坑里面时,结束了
if(steps[current_index] == 0)
return 600;
printf("跳跃到第%d个格子\n",theBestChoise);
times++;
}
//看pre_index 能否被超过
if(pre_index < i+steps[i]){
theBestChoise = i;
pre_index = i+steps[i];
if(pre_index >= steps.size()-1){ //能够到终点了,直接退出
times = times + 2; //这里连续跳了两步
printf("跳跃到第%d个格子,然后直接跳到终点\n",theBestChoise);
break;
}
}
}
if(pre_index < steps.size()-1)
return 600;
return times;
}
};
3.完整代码
#include
#include
using namespace std;
class Solution{
public:
int jumpGame2(vector steps){
//如果格子小于等于1,返回错误1,一步都不跳
if(steps.size() <= 1)
return 0;
//current_index = steps[a]+a;
int current_index = steps[0];
//pre_index = (a,b] 之间的能去到的最远距离
int pre_index = steps[0];
//跳跃次数
int times = 0;
//记录每次跳哪一步
int theBestChoise = 0;
for(int i = 1;i < steps.size();i++){
//指针来到 b+1的位置,不得不跳出一步
if(i > current_index){
current_index = pre_index;
//不得不走一步,只能走到一个坑里面时,结束了
if(steps[current_index] == 0)
return 600;
printf("跳跃到第%d个格子\n",theBestChoise);
times++;
}
//看pre_index 能否被超过
if(pre_index < i+steps[i]){
theBestChoise = i;
pre_index = i+steps[i];
if(pre_index >= steps.size()-1){ //能够到终点了,直接退出
times = times + 2; //这里连续跳了两步
printf("跳跃到第%d个格子,然后直接跳到终点\n",theBestChoise);
break;
}
}
}
}
};
int main(){
vector steps;
steps.push_back(1);
steps.push_back(1);
steps.push_back(3);
steps.push_back(2);
steps.push_back(1);
//steps.push_back(0); //注释这一行看这个坑有没有起效
steps.push_back(2);
steps.push_back(3);
steps.push_back(5);
steps.push_back(2);
Solution solve;
int result = solve.jumpGame2(steps);
if(result == 0)
printf("你只有一个格子或者一个格子都没有,跳0步!");
else if(result == 600)
printf("你不得不跳入一个坑中,结束一生!");
else
printf("总共需要跳跃%d步!",result);
}
有一些贪心算法的题目的贪心思想就是
我要尽量贪心,就要用最少的资源做最好的事情
怎么用最少的资源呢?就是不得不用,我再去用,这个很关键
分析题目的时候,要找到那个不得不用的时刻,题目就自然得解