Leetcode——45Jump GameII

本周做的是一道关于贪心思想的题目,在实现过程中主要用到的算法是BFS~

一、题目描述

    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.

Your goal is to reach the last index in the minimum number of jumps.

For example:
Given array A = [2,3,1,1,4]

The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then 3 steps to the last index.)

   给出一个非负数组,起始位置在数组第一个下标处,终点在数组的最后一个下标处。数组的每一个元素表示的是在该位置时,最多能够跳多远。

   举个例子,数组A = [2, 3, 1, 1, 4],表示起点是0,终点是4,在起点处可跳跃的步数是1和2,如果跳了2步,到的位置是下标2的地方;A[2]的值是1,说明可跳跃的步数是1,到的位置是下标为3的地方;A[3]的的值是1,同样说明可跳跃的步数是1,到的位置是下标为4的地方,到达目标终点位置。该题目要求的,是使用最少的步数到达终点。在上述例子中,最少步数应该是2,从起始位跳1步到第一个位置,从第一个位置跳3步直接到终点。


二、解题思路

    首先思考的问题是,贪心算法的思想是什么?


贪心算法总是选择在当前看起来是最好的一种情况,通过一系列局部最优的选择,希望能够得到整体的最优解。它的两个重要性质是:1)一个整体能够分为多个局部,且这些局部都能求出最优解;2)整体的最优解可以通过局部的最优解来得到。


    本题要求的整体是以最少的步数从起点去到目标位置,那么局部问题是从当前位置到下一位置的最优解是什么?每一步跳得更远,使得到达目的也越快。因此,局部最优是能够跳得最远距离。只要保证每一步都是跳最远,就非常有可能在最小的步数到达目标。但是,若下一个最远距离和前面部分最优解连在一起不再是可行解时,就不把下一个的数据添加到部分解中,直到把所有数据枚举完,或者不能再添加算法停止。

     

    其次,思考的问题是,使用何种方式来实现该算法?


  每一个位置可以跳跃的下一位置的选择是与给定的数组有关,给定起点和终点,如果把这个跳跃的过程想成一个有向图,每一个位置是一个节点,那么就是找从起点到终点的最短路径。


     因此,本题的思路是按数组大小n设定节点数,从0到n-1,利用数组给出的最大跳跃长度,即在某一节点能够去到的节点位置,构造一个有向图。在这个有向图中进行BFS,找到从起点到终点的最短路径。还是上面的例子A = [2, 3, 1, 1, 4],将数组信息转换为图信息,构造的有向图是:

 

    由图可以看出,从节点0到节点4的最短路径是0→1→4,即2步。

   在实现的过程中,记数组为nums,如果使用邻接表,将所有节点可以到达的邻接点先记录下来,再进行BFS遍历,需要的时间很长,容易超时。因此,可以采用直接采用以下步骤进行BFS:

1)将起点入队,将起点的dist[0]赋值为0,进入循环;

2)当队列不为空:

a) 取队头元素front;

b) 下一步可去到的位置是front + nums[front]到front + 1,为了使能够以最小的步数到达终点,所以从i = front + nums[front]开始,取可以跳跃的最长距离,依次递减,如果到达的位置没有超过终点位置tar,且该位置没有被访问过,那么将该位置入队,并记下从起点到该位置的距离,即dist[i] = dist[f] + 1。如果到达的位置刚好是tar,那么记录下dist[i],并结束循环,进入步骤3);否则继续循环;

c) 队头元素要记住pop;

3)输出dist[tar]即为最小步数。

三、代码展示

//主要思路:通过BFS找最短路径
int jump(vector<int>& nums) {
	//如果只有一个元素,说明一开始就在起点,不需要走,仅需要0步
	if(nums.size() == 1)
			return 0;

	//目标所在,即是数组的最后一个下标
	int tar = nums.size()-1;
	//定义一个距离数组,记录从起点到某个位置的步数
	int dist[nums.size()];
	int i;
	for(i = 0; i <= tar; i ++)
		dist[i] = INT_MAX;
	queue<int> q;
	q.push(0);
	int f;
	//从起点0开始,按照BFS的方法,找到从起点到终点的最短路径
	dist[0] = 0;
	while(!q.empty()){
		f = q.front();
		//循环变量i从当前点的可走最大步数开始检查
		for(i = f+nums[f]; i > f; i --)
			//如果跳跃的位置不会超过终点,且该位置没有走过,该位置入队
			if(i <= tar && dist[i] == INT_MAX){
				q.push(i);
				dist[i] = dist[f] + 1;
				//如果刚好跳过去就是终点,那么直接结束循环
				if(i == tar)
					break;
			}
		//到达终点,直接结束循环
		if(i == tar)
			break;
		q.pop();
		//cout << f<< endl;
	}
	if(i == tar)
		return dist[tar];
	else
		return 0;
}

总结:   

 实际上这道题涉及的算法主要还是BFS(虽然它的标签是Greedy),贪心的思想是每次选择跳跃最远距离,可以最少步数的到达终点。虽然并不是所有的贪心选择都是最优解,但是大多数情况下都能最快找到最少步数。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值