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.
题意:
给定一个由非负整数组成的数列,从第一个元素位置作为初始处,往后跳跃 每次可以跳的最远距离为此处元素的值,求至少需要跳跃多少次可以到达最后一个元素。题目保证有解。
分析:
从前往后跳跃,每次有1--- nums[i]种跳法,并且到达每一位置的最少跳跃次数受前一次结果的影响,因此可以使用DP,主要思路如下:
- 构建与所给数列同等大小的dp,并用INT_MAX初始化dp,表示初始到达所有位置的跳跃次数;
- 将dp[0] 置为 0 ,因为从0处出发。
- 遍历数列,并且以当前位置为跳跃点,更新所能到达的所有位置,更新到达后面每一位置的最小跳跃数。
- 过滤掉当前位置后面连续的若干 个跳跃范围被当前位置所覆盖的点(节省不必要的计算,负责边界值会超时)即2,3,1,1,4,5 这种情况 当遍历到3的时候,后面的两个1的位置其实是没有意义的,因为它们的可跳跃范围已经被3所包含在内。
Code & C++
class Solution {
public:
int jump(vector<int>& nums) {
std::ios::sync_with_stdio(0);
cin.tie(0);
int len = nums.size();
if(len<=1)return 0;
vector<int> dp(len, INT_MAX);
int j,idx;
dp[0]=0;
for(int i=0;i<len;++i){
j=1;
// 更新当前位置可以到达的位置的跳跃需求次数
while(j<=nums[i] && i+j<len){
dp[i+j]=min(dp[i]+1, dp[i+j]);
++j;
}
idx=1;
// 过滤当前位置所覆盖了的起跳位置
while(i+idx<len && nums[i+idx]+idx<=nums[i])++idx;
i+=idx-1;
}
return dp[len-1];
}
};
Code & Python
class Solution:
def jump(self, nums: List[int]) -> int:
nlen = len(nums)
dp = [1<<31]*nlen
dp[0], i = 0, 0
while i < nlen:
j, idx = 1, 1
flag = True
while i+j < nlen and j <= nums[i]:
dp[i+j] = min(dp[i+j], dp[i]+1)
if flag and nums[i+j]+j <= nums[i]:
idx = j
else:
flag = False
j += 1
if idx>1:
i += idx-1
else:
i += 1
return dp[nlen-1]
Runtime: 68 ms, faster than 37.84% of Python3 online submissions for Jump Game II.
Memory Usage: 14.5 MB, less than 7.50% of Python3 online submissions for Jump Game II.