2.跳跃游戏(c++)

一、题目

有一段直线距离,这段距离上分布着 n 个 格子

每个位置上都标有数字,表示可以从这个格子往前最多跳跃几格

最少跳几步,可以从起点跳到终点?

如上图就是需要从A点跳到C点

在A点,可以往前最多跳2格,也就是在A点 可以往前跳一格或者两格

B点就可以看成一个坑,像上图这个例子中,这个坑就是没办法逾越的,所以没办法跳到终点

二、分析

这道题目被归类为贪心算法

贪心算法都有个贪心思想

既然我需要得到最少跳几步,那么我就死活不跳

到了不得不跳的时候,再挑一个跳的最远的位置,来跳

定义a为当前格子,b为当前格子能到的最远距离

像上面这个例子

把A点看成 a,把A点能跳到的最远距离看成 b(也就是第三个位置)

什么叫不得不跳?

A只能走一步或者两步,而我现在就在A点,那么就要考虑在(a,b] 这段距离内

哪个格子能够尽可能地跳的更远,而且一定要选一个格子跳

也就是每次来到一个新格子,就要考察(a,b] 那个格子能跳的更远

所以这里的贪心思想是:不得不跳我再跳,跳了我就选最大的跳

这里我们可能会思考这个“坑”怎么考虑,因为每次选最好的格子跳

最后如果最远只能跳到一个坑里,那自然就是没法越过这个坑,返回失败即可

三、代码

 1.main函数

这里我们的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);
}

2.解决方案Solution

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);
}

四、小结

有一些贪心算法的题目的贪心思想就是

我要尽量贪心,就要用最少的资源做最好的事情

怎么用最少的资源呢?就是不得不用,我再去用,这个很关键

分析题目的时候,要找到那个不得不用的时刻,题目就自然得解

你可能感兴趣的:(算法)