给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
示例:
输入: [2,3,1,1,4] 输出: 2 解释: 跳到最后一个位置的最小跳跃数是 2。 从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
说明:
假设你总是可以到达数组的最后一个位置。
正确思路:
https://blog.csdn.net/scarlett_guan/article/details/80159621
贪心算法:
思路:贪心法来做,时间复杂度O(n). 用变量aa来记录上一次能达到的最远位置,times记录所用的最小跳跃数,说明times步区能达到的最远位置是aa,比如在input{ 7, 0, 9, 6, 9, 6, 1, 7, 9, 0, 1, 2, 9, 0, 3},这个区间内,1步区所能达到的最远位置是7。在 i 到达aa(7)之前,所有的位置都可以通过times步数(1步)来达到,因此这个区间之内,每一个点当前可以达到的最远位置bb= max(bb, nums[i]+i),最小跳跃数为times+1(2步)。到了i=aa(即i==7)的时候,更新aa=max(bb, aa+nums[aa])=14, ++times, 也就是说标志着1步区的结束,2步区的开始,此时2步区所能达到的最远位置为aa=14。成为下一阶段3步区的前一个最优解。重复该过程。
class Solution {
public:
int jump(vector<int>& nums) {
if (nums.size() == 1) return 0;
int aa = nums[0], times = 1, bb=aa;//1步最远可以到多远
for (int i = 1; i < nums.size(); ++i){
if (aa >= nums.size() - 1) return times;
while (i < aa){
bb = max(bb, nums[i] + i);
++i;
}
aa = max(bb,aa+nums[aa]);
++times;
}
}
};
这里的i<aa不能变成i<=aa。
这样++i可能直接就跳出循环了。
我的思路:
根据跳跃游戏1进行判断,同时不断更新dp数组,数组内记录着最少的步数
还是会超时。
class Solution {
public:
int jump(vector<int>& nums) {
int* dp=new int[nums.size()]();
int reach=0;
bool* flag=new bool[nums.size()]();
for(int i=0;i<nums.size();i++)
{
int tmp=i+1;
while(tmp<=i+nums[i]&&tmp<=nums.size()-1){
if(flag[tmp]==0)
dp[tmp]=dp[i]+1;
else
dp[tmp]=min(dp[i]+1,dp[tmp]);
flag[tmp]=1;
tmp++;
}
reach=max(reach,i+nums[i]);
if(reach<=i&&reach!=nums.size()-1)
return 0;
}
return dp[nums.size()-1];
}
};
优化了一下:
还是剩一个超时:
class Solution {
public:
int jump(vector<int>& nums) {
int* dp=new int[nums.size()]();
int reach=0;
bool* flag=new bool[nums.size()]();
for(int i=0;i<nums.size();i++)
{
int tmp=i+1;
while(tmp<=i+nums[i]){
if(flag[tmp]==0)
dp[tmp]=dp[i]+1;
flag[tmp]=1;
if(tmp==nums.size()-1)//贪心的思想,最先到达这里的肯定是最快的
return dp[tmp];
tmp++;
}
reach=max(reach,i+nums[i]);
if(reach<=i&&reach!=nums.size()-1)
return 0;
}
return dp[nums.size()-1];
}
};