我自己解了一个方法,又借鉴网上的贪心算法又写了一遍代码。如下。
第一个是贪心算法,遍历元素,维护的指标为当前能够达到的最大值,该最大值是比较上一循环的最大值和当前根据规则做运算的结果进行比较得来的。这个方法是网上最常用的方法。相关注意事项见代码注释。
// 第三遍提交:看网上的贪心算法,自己也写了一个
// 最后在做一些说明。这里应用贪心算法,,第一,一定遍历所有元素,而不是跳跃。第二注意maxreach的更新方法:是上一个循环能够达到的最大值,和当前能够达到的最大值即i+nums[i]之间的较大者。
public:
bool canJump(vector<int>& nums)
{
int N = nums.size();
int maxreach = 0; //注意是下标值,而不是元素值
for(int i = 0; i !=N;++i)
{
if(i > maxreach) //注意false的条件,就是maxreach停止了,而i仍然在增加,一直到超过maxreach也没有停止,对应题目中的反例很好理解
return false;
maxreach = max(maxreach, i + nums[i]); //注意更新方法
if (maxreach >= N-1) //一个小细节,要写成>=而不是写成==
return true;
}
}
};
结果如下:
然后是自己的方法
首先要有一个观点:原数组中有0才可能过去不,没有0一定能够过去;因此主要的思路是找到原数组中为0的元素,对每一个为0的元素都查看是否可以过去;对于是否能够过去,写一个private函数来完成。重点是:不能过去的充要条件是,0之前所有元素值不大于该元素与0的距离。这里有一个小问题未得到解决,就是每找到一个0,都得从原数组的开始进行判断,暂时没找到更简单的逻辑。当然这个方法需要对一些退化的情况进行处理,贪心算法甚至不需要对退化情况进行处理。代码如下:
class Solution
{
// 第二遍提交:主要是精简代码
// 主要的思路就是找到为0的元素,看其前方元素能否越过该0
public:
bool canJump(vector<int>& nums)
{
int N = nums.size();
if (N<= 1) // nums规模为0或者1
return true;
if (nums[0] == 0) // num规模大于等于2,但首元素就是0
return false;
for (int i = 1; i!=N-1;++i ) // 遍历到倒数第二个就可以了
{
if (nums[i] == 0)
{
vector<int> subnums(nums.begin(), nums.begin() + i); // 注意这里加的数字i
if (!jumpZERO(subnums))
return false;
}
}
return true;
}
private:
// 一个数组末位是0,判断能否越过该0
//参数ivec最后一个元素不是0,调用它的数组中,它后面是0
bool jumpZERO(vector<int> ivec)
{
for(auto iter = ivec.begin();iter != ivec.end();iter++)
{
if (*iter > (ivec.end()- iter) )
return true; // 距离末位元素(0)只要有一个值大于距离值, 就可以越过
}
return false; // 都不大于距离值,无法越过
}
};
结果如下: