题目描述
给出一组正整数,你从第一个数向最后一个数方向跳跃,每次至少跳跃1格,每个数的值表示你从这个位置可以跳跃的最大长度。计算如何以最少的跳跃次数跳到最后一个数。
输入描述:
第一行表示有多少个数n
第二行开始依次是1到n个数,一个数一行
输出描述:
输出一行,表示最少跳跃的次数。
示例1
输入
7
2
3
2
1
2
1
5
输出
3
说明
7表示接下来要输入7个正整数,从2开始。数字本身代表可以跳跃的最大步长,此时有2种跳法,为2-2-2-5和2-3-2-5都为3步
解题思路:如何选择步长是关键。
我的解题思路过程如下:
(1)把最后一个数当作终点,从最后一个数开始,往前找,找到一个可以一步到达终点且距离终点最远的那个数;
(2)把刚刚找到的数,作为终点,重复(1)的步骤
(3)到达起点的数时,就终止。
怎么理解“可以一步到达终点且距离终点最远”呢?
如上图,肯定选择2,而不是1.
实际上就是保证每一步跨越尽可能大的距离,那么需要走的步数肯定就是最小的。
思路是对的,但是在代码实现的时候出现问题了,如何保证你找到的那个位置的数就是“可以一步到达终点且距离终点最远”呢?这样就必须一直遍历到起点才能知道,这就存在很大的时间消耗了。
既然是距离终点最远,那么反过来,就是距离起点最近,
所以解题思路换成如下:
(1)从起点开始,找到第一个可以一步到达终点的位置;
(2)把刚刚找到的位置作为新的终点,重复(1);
(3)直到新的终点和起点重合,结束。
思路出来了,代码就很简单了,就是个简单的递归,而且时间消耗也不会很大,因为每次递归时只需要找到第一个可以一步到达终点的位置即可。
附上源码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] num = new int[n];
for (int i = 0; i < n; i++)
num[i] = sc.nextInt();
sc.close();
System.out.println(jump(n - 1, num));
}
public static int jump(int end, int[] num) {
if (end == 0)
return 0;
int i = 0;
while (num[i] < (end - i))
i++;
return 1+jump(i, num);
}
}