55. Jump Game
题意理解:
数组中的每个元素代表最多向后能够跳跃的距离,求解是否能够到达最后的一个元素;
思路
最简单的方法来思考这个问题是问的元素与0的价值是可以避免的吗?这是我构造来回答这个问题的算法,从数组中的第二到最后一个元素,我们将继续递减数组的开始。只有当我们击中一个值为0的元素时,才会停止;在这种情况下,我们评估如果数组的某个地方存在一个元素,该元素的跳值足够大,可以跳过这个0值元素。
97%
public boolean canJump(int[] nums) {
if(nums.length <= 1) return true;
for(int i = nums.length - 2; i >= 0; i--) {
if(nums[i] == 0) {
int need = 1;
while(need > nums[i]) {
need++;
i--;
if(i < 0) return false;
}
}
}
return true;
}
45. Jump Game II
这里用一种巧妙并且不太容易理解的贪心算法可以达到O(N)的时间复杂度,只不过在算法中要记录当前一跳所能到达的最远距离、上一跳所能到达的最远距离,和当前所使用跳数就可以了。另外需要注意的一点是:题意要求不一定非得跳到last index,越过去也算,这点需要特别强调。
public int jump(int[] nums) {
int ret = 0;//当前跳数
int last = 0;//上一跳可达最远距离
int cur = 0;//当前一跳可达最远距
for (int i = 0; i < nums.length; ++i) {
//无法向前继跳直接返回
if(i>cur){ //有可能无论怎么跳,都不能到达终点或者越过终点,比如[3,2,1,0,4]。
return -1;
}
//需要进行下次跳跃,则更新last和当执行的跳数ret
if (i > last) {
last = cur;
++ret;
}
//记录当前可达的最远点
cur = Math.max(cur, i+nums[i]);
}
return ret;
}
接下来,第一元素告诉cur,可以向前走2步。于是:
下一循环中,i指向index 1(图中的元素3),发现i大于last能到的范围,于是进行跳跃。步数ret加1.同时要更新cur。因为发现了新的最远距离。
接下来,i继续前进,发现i=last,无需更新last和步数ret。更新cur。
i继续前进,发现i>last,更新last和步数。cur已经最大了。
最后,i到最后一个元素。遍历完成,返回ret。