题目难度: Medium
原题描述:
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.
Determine if you are able to reach the last index.
For example:
A = [2,3,1,1,4]
, return true
.
A = [3,2,1,0,4]
, return false
.
题目大意:
给你一个有非负整数的数组,每一个数代表在这个位置上最多能往前走的步数,假设你现在在数组的第一个位置上,问是否能到达数组的最后一个位置。
解题思路:
一开始我想到了两个算法,但都是O(n^2)的。第一个是类似动态规划的思想,从前往后逐个判断当前位置能否到达,在判断能否到达每一个位置的时候需要遍历从第一个位置到当前位置的前一个位置,看其能否到达当前位置,如果其中有一个可以到达,则当前位置可以到达,这样一直到最后一个位置就可以得到结果。这里要注意的是,如果在数组中有一个位置不可到达,则后面的位置也不可能到达,因此可以直接返回false。
第二个算法是dfs。对于数组中的每一个位置,建立它能够到达的后面位置的边,这样就构造了一个有向无环图。然后从第一个位置开始dfs,看其是否能到达最后一个位置。dfs的时间复杂度是O(V+E),当边数很多的时候,E接近V^2,时间复杂度就变成了O(V^2)。
但是可惜的是,这两个算法都超时了(dfs栈溢出了),因此这两个算法都不是最佳的算法。在网上参考了别人O(n)的算法,确实很简洁,思想简单却深刻。算法的思想是:维护一个能到达的最远位置的reach,对于每一个小于等于reach的位置,如果当前位置能到达的位置大于reach,则更新reach。最后判断reach大于等于最后一个位置就行了。
时间复杂度分析:
最后一种算法只需遍历一次数组,因此时间复杂度为O(n)。
以下是代码:
public boolean canJump(int[] nums)
{
int reach = 0;
int n = nums.length;
for(int i=0 ; i<n-1 && i<=reach ; ++i){
reach = Math.max(reach, i+nums[i]);
}
if(reach >= n-1){
return true;
}
else{
return false;
}
}