题目
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
示例:
输入: [2,3,1,1,4] 输出: 2 解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。 说明:假设你总是可以到达数组的最后一个位置。
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/jump-game-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
分析
动态规划,记录到某个位置的时候需要的最小步数。当能够到达一个新位置的时候比较(原来位置的步数+1)和(已经保存的最小步数),记录更新为更小的那个。
先尝试最暴力的手段。
代码
#define min(a,b) ((a)<(b)?(a):(b))
#define MAXSIZE 2147483647
int jump(int* nums, int numsSize){
if (numsSize == 0 || numsSize == 1) return 0;
int a[numsSize];
a[0] = 0;
for (int i = 1; i<numsSize ; i++){
a[i] = MAXSIZE;
}
for (int i = 0; i < numsSize ; i++){
if (a[i] == MAXSIZE) return -1;
for (int j = 0; j < nums[i] ; j++){
if (i+j+1 >= numsSize) break;
a[i+j+1] = min(a[i]+1,a[i+j+1]);
}
}
return a[numsSize-1];
}
运行结果:
分析2
毕竟是困难难度的题目,果然没有那么简单……
不得不说我的算法在时间复杂度上确实存在很大的优化空间。既然是超时,那么首先考虑算法的优化问题。因为我现在对每一个位置都需要进行多次更新,题目中又允许我们假定一定可以到最后一格,那么我们是否可以用贪心算法解决?每次我都尽可能地优先更新走的最远的那个格子,但是这样有个问题就是可能需要回溯(相当于要进行深度优先的搜索),那就需要记录跳跃的路径(当作回溯点),有没有避免回溯的方法呢……我想到了一种算法算是避免了回溯。
那就是贪心算法:每一步都尽可能的往远处走,我只需要记录最远那个格子以及它对应的步数就可以了,这样不但可以避免回溯,甚至可以在O(n)的条件下(而且最多遍历一次)完成题目要求。只需要从左往右遍历就可以。
如果采用从后往前遍历的话很可能会漏过某些更快到达的途径。
代码2
#define max(a,b) ((a)>(b)?(a):(b))
int jump(int* nums, int numsSize){
int step = 0,end = 0 , farthest = 0,len = numsSize - 1;
for (int i = 0; i < len; i++){
farthest = max(nums[i] + i, farthest);
if (i == end){
end = farthest;
step++;
}
}
return step;
}
运行结果2
令人满意。这题其实只能算中等难度吧。