一、
题目描述
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个位置。
示例 1:
输入: [2,3,1,1,4] 输出: true 解释: 从位置 0 到 1 跳 1 步, 然后跳 3 步到达最后一个位置。
示例 2:
输入: [3,2,1,0,4] 输出: false 解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。
思路一:
使用动态规划的想法,用额外的数组记录可以到达的位置,然后通过reach[n-1]来判断
可以解题,但是速度太慢。
class Solution { public: bool canJump(vector<int>& nums) { int n=nums.size(); if(n<2) return true; vector<bool> reach(n,false); reach[0]=true; for(int i=0;i<n;++i) { if(reach[i]) { for(int j=1;j<=nums[i]&&i+j<n;j++) { reach[i+j]=true; } if(reach[n-1]) return true; } } return reach[n-1]; } };
思路二:
- 每次到一个位置 i,判断 maxS 最远可到的位置下标能不能到达 i
- 能到达,则在当前位置可达的最远位置下标为 nums[i] + i , 取其与 maxS 的大者为最远可达位置
- 循环判断
class Solution { public: bool canJump(vector<int>& nums) { int maxS = 0, i; for(i = 0; i < nums.size(); ++i) { if(maxS < i) return false; maxS = max(maxS, nums[i]+i); } return true; } };
class Solution { public: bool canJump(vector<int>& nums) { int n=nums.size(); int maxLen=0; for(int i=0;i<n;++i) { if(i<=maxLen) { maxLen=max(maxLen, i+nums[i]); if(maxLen>=n-1) return true; } } return false; } };
二、
题目描述
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
示例:
输入: [2,3,1,1,4]输出: 2解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
说明:假设你总是可以到达数组的最后一个位置。
思路:
这道题的最优解是可以时间复杂度优化到 O(n) 的,那就是采用贪心算法,我们从左边的起点开始跳跃的时候,我们应该跳跃到哪一个点比较合适呢?,显然,每次都跳跃最大长度的话,是不行的。例如对于上面 arr = {2, 3, 1, 1, 4, 2, 1} 这个例子,刚开 arr[0] = 2,那么我们可以跳到 arr[1] = 3 或者 arr[2] = 1 上,显然,我们跳跃 arr[1] = 3 会更好一点。如图(图片来源于网络)
接着同样的道理,我们可以从 arr[1] = 3 这个位置开始跳跃,它可以跳跃到 arr[2] = 1, arr[3] = 1, arr[4] = 4 这三个位置,显然,我们跳到 arr[4] = 4 这个位置好一点,如图(图片来源于网络)
也就是说,我们要跳跃的那个点,可以使得上一次 + 下一次的跳跃总距离最远。代码如下
class Solution { public: int jump(vector<int>& nums) { int step=0,end=0,maxS=0; for(int i=0;i<nums.size()-1;++i) { maxS=max(maxS,i+nums[i]); if(i==end) { end=maxS; step++; } } return step; } };