LeetCode解题 45:Jump Game II
Problem 45: Jump Game II [Hard]
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.
Example:
Input: [2,3,1,1,4]
Output: 2
Explanation: 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.
Note:
You can assume that you can always reach the last index.
来源:LeetCode
解题思路
1. 暴力搜索(不剪枝)
从后往前遍历数组,计算每个位置能够到达数组末尾的最小跳跃次数。
具体方法: 由于从后往前遍历,因此位于每个位置后方的跳跃点都已经计算过最小跳跃次数,只需要在当前位置能够跳跃的范围内搜索一个最小值,再加上1,即为当前位置的最小跳跃次数。一直遍历到nums[0]就能算出从数组头部到末尾的最小跳跃次数。
缺点: 该方法计算出了每一个位置上的最小跳跃次数,没有剪去一些不必要的搜索过程,最坏情况下复杂度为
1
2
n
2
\frac{1}{2}n^2
21n2.
2. 贪心算法
利用贪心算法的思想:
一个点选择下一个跳跃点的原则为:下一个跳跃点拥有最广的视野。可以解释为,它在当前点可选择范围内能够拥有最广的未来跳跃选择,那么它的跳跃次数一定最小。也就是在每个位置index
的搜索过程中,选择下一个跳跃点的公式为:
n
e
x
t
_
p
o
i
n
t
=
arg max
i
{
i
+
n
u
m
s
[
i
]
}
next\_point = \argmax_i\{i + nums[i]\}\\
next_point=iargmax{i+nums[i]}
其中,
i
∈
[
i
n
d
e
x
+
1
,
i
n
d
e
x
+
n
u
m
s
[
i
n
d
e
x
]
]
i \in [index + 1, index + nums[index]]
i∈[index+1,index+nums[index]],然后对
n
e
x
t
_
p
o
i
n
t
next\_point
next_point进行递归搜索。
优点: 每一次搜索都只选择一个点进行递归搜索,可以省去暴力搜索中的大部分搜索过程,事实证明这些搜索过程都是不必要的。使用贪心算法之后,时间复杂度减小为O(n)。
具体过程:
- 使用递归搜索,从
index=0
开始,直到index + nums[index] >= N-1
时结束,每次递归深度增加时,返回的跳跃步数+1。 - 在每个位置index的搜索过程中,搜索范围为当前位置能够跳跃的范围(
index+1 ~ index + nums[index]
),在该范围中找到一个能够在未来跳得最远的点,作为下一层递归的起始点。 - 递归结束条件:
a. 当前点能够一步跳到数组末尾(index + nums[index] >= N-1),直接返回1。
b. 在搜索下一个跳跃点时,发现跳跃范围内有点可以一步跳到数组末尾,直接返回2。
运行结果:
Solution (Java)
暴力搜索:
class Solution {
public int jump(int[] nums) {
int N = nums.length;
if (N == 0 || N == 1) return 0;
if (N == 2) return 1;
int[] jumps = new int[N];
jumps[N - 1] = 0;
for(int i = N - 2; i >= 0; i--){
if(nums[i] == 0){
jumps[i] = N;
}
else if(i + nums[i] >= N - 1){
jumps[i] = 1;
}
else{
int min = N;
for(int j = i + 1; j <= i + nums[i]; j++){
if(jumps[j] < min){
min = jumps[j];
}
}
jumps[i] = min + 1;
}
}
return jumps[0];
}
}
贪心算法:
class Solution {
public int jump(int[] nums) {
int N = nums.length;
if (N == 0 || N == 1) return 0;
if (N == 2) return 1;
return maxCover(0, nums, N);
}
protected int maxCover(int start, int[] nums, int N){
if(start + nums[start] >= N - 1) return 1;
int max = 0;
int next_start = start;
for(int i = start + 1; i <= start + nums[start]; i++){
if(i + nums[i] >= N - 1) return 2;
if(i + nums[i] > max){
max = i + nums[i];
next_start = i;
}
}
return maxCover(next_start, nums, N) + 1;
}
}
修改过程
- 第一次提交了暴力搜索的解法,系统判时335ms,修改为贪心算法后只需1ms。