注意:之前我曾就此算法提出过另一个问题,但这个问题澄清了时间复杂性问题。
使用以下算法:
给定一组非负整数,您最初定位 在数组的第一个索引处。
数组中的每个元素代表你的最大跳跃长度 位置。
确定您是否能够到达最后一个索引。
例如:
A = [2,3,1,1,4]
,返回true
。A = [3,2,1,0,4]
,返回false
。
在根据我以前的SO帖子进行优化之前,下面是我最初的蛮力(带记忆)解决方案Speeding up solution to algorithm
在那个问题上,我与其他用户讨论了我的初始算法的时间复杂性,我只是想确保我正确理解。下面的代码是O(N)时间算法正确吗?我的代码超时用于大测试输入,所以我假设它是一个非常慢的O(N)......但仍然是O(N)而不是O(N ^ 2)正确吗?因为memoization节省了可跳跃?对于每个指数,如果我没有弄错..
@memo = {}
def can_jump(nums)
@memo = {}
jumpable?(nums, 0) #new approach. launch a function for each index, memoize to get O(N) time. should be the same shit.
end
def jumpable?(nums, curr_idx)
return true if curr_idx >= nums.length - 1 || nums.length == 1
i = curr_idx
true_counter = 0
curr_val = nums[i]
curr_val.downto(1) do |num|
@memo[curr_idx + num] ||= jumpable?(nums, curr_idx + num )
true_counter +=1 if @memo[curr_idx + num]
end
true_counter > 0
end
答案 0 :(得分:0)
您的算法在O(n^2)
中运行,而非O(n)
。
我将以一个例子来证明这一点。假设您的输入是以下n长度数组:
[n-2, n-3, n-4, ..., 2, 1, 0, 0]
也就是说,数组的i
元素等于n-2-i
(除了最后一个元素,其值是任意的,因为它不会对结果产生影响)。显然,算法将返回false
以进行上述输入。遗憾的是,在使用上述输入数组时,我们要做的工作量是O(n^2)
。
我们从位置0
开始,看到我们最多可以跳n-2
步。然后:
n-1
位置,看看我们无法从那里跳到任何地方。n-2
位置,看看我们可以跳到以下位置:
n-1
n-3
位置,看看我们可以跳到以下位置:
n-1
n-2
n-4
位置,看看我们可以跳到以下位置:
n-1
n-2
n-3
1
位置,看看我们可以跳到以下位置:
n-1
n-2
2
观察每个子弹的子弹代表我们必须尝试跳跃的位置(我们要发现它们中的每一个都是死路一条,但我们仍然会尝试跳到那里)。因此,我们尝试检查是否可以跳转到特定位置的总次数是:
0 + 1 + 2 + ... + (n-2) = (n-1)(n-2)/2 = O(n^2)
因此,你的算法没有你想象的那么快的原因是因为它不是线性的而是二次的。