题目概述
解题思路
这道题的题意是说,告诉我们一条石子路上有哪些位置的石子可以落脚,以及每一次能跳的距离的范围,问我们能不能跳到终点。
我的想法一开始是直接用动态规划,开一个一维数组记录每个石子能否落脚,然后对每个石子都算一下从它出发所能访问的石子有哪些,更新这些石子的状态即可。假设路程长度为N,跳跃范围为K,则时间复杂度为O(N*K)。这显然是不可接受的_(:з」∠)_
然后我就在想,能否只访问一遍每个元素(O(N)时间复杂度),就得到结果呢?
实际上是可行的。我们在起始的位置相当于可以获悉1 + K个位置的访问状态(初始位置+[minJump, maxJump]);从第二个位置开始,如果这个位置是可访问的,那么它比上一个位置多了一个可访问的位置,所以只需要访问一次,而不是再访问K次;如果这个位置不可访问呢,我们自然而然会继续让我们的指针遍历下一个石子。这里需要注意的是,如果接下来的石子都不可访问,那我们下次碰到的可访问石子就需要像从起始位置出发一样,遍历[当前位置+minJump, 当前位置+maxJump],这就需要我们维护一个变量curLen,来记录当前所能访问到的最远距离的石子。然后每次遇到新的石子,我们就去遍历[max(当前位置+minJump, curLen), 当前位置+maxjump]了。
方法性能
示例代码
class Solution {
public:
bool canReach(string s, int minJump, int maxJump)
{
int len = s.size(), farther = 0;
vector<bool> vis(len, false); //record whether we can visit each position
vis[0] = true;
bool sig = 1;
for(int i = 0; i < len - minJump; ++i)
{
if(vis[i] == true)
{
if(sig)
{
for(int j = minJump; j <= maxJump && (i + j < len); ++j)
{
if(s[i + j] == '0')
vis[i + j] = true;
}
sig = false;
}
else
{
for(int j = max(minJump, farther - i); j <= maxJump && (i + j < len); ++j)
{
if(s[i + j] == '0')
vis[i + j] = true;
}
}
farther = i + maxJump;
}
}
return vis[len - 1];
}
};