跳跃游戏: 给定一个数组,从第一个元素开始,通过跳转到达最后一个元素。跳转长度最多可以是数组中当前位置的值。最佳结果是当您以最小跳跃次数达到目标时。
找到最佳结果的算法是什么?
一个例子:给定数组A = {2,3,1,1,4}到达目的地的可能方式(索引列表)是
由于第二种解决方案只有2次跳跃,因此是最佳结果。
答案 0 :(得分:16)
根据您的数组a
和当前位置i
的索引,重复以下操作,直至到达最后一个元素。
考虑a[i+1]
到a[a[i] + i]
中的所有候选“跳转元素”。对于索引为e
的每个此类元素,请计算v
= a[e]
+ e
。如果其中一个元素是最后一个元素,则跳转到最后一个元素。否则,跳转到具有最大v
的元素。
更简单地说,在触手可及的元素中,寻找能够让你在 next 跳跃中获得最远的元素。我们知道这个选择x
是正确的,因为与您可以跳转到的每个其他元素y
相比,从y
可到达的元素是可以从{{到达的元素的子集1}}(向后跳转的元素除外,这显然是错误的选择)。
此算法在O(n)中运行,因为每个元素只需要考虑一次(可以跳过被认为是第二次的元素)。
考虑值数组x
,标记,a
以及索引和值i
的总和。
v
从索引0开始,考虑接下来的4个元素。找到最大i -> 0 1 2 3 4 5 6 7 8 9 10 11 12
a -> [4, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
v -> 4 12 3 4 5 6 7 8 9 10 11 12 13
的那个。该元素位于索引1处,因此跳转到1.现在考虑接下来的11个元素。目标是可以实现的,所以跳到目标。
请参阅here或here with code。
答案 1 :(得分:6)
动态编程。
想象一下,您有一个数组B
,其中B[i]
显示了在数组i
中达到索引A
所需的最小步数。你的回答当然是B[n]
,给定A
有n
个元素,索引从1开始。假设C[i]=j
表示你从索引j跳到索引i(这是恢复以后采取的路径)
所以,算法如下:
set B[i] to infinity for all i
B[1] = 0; <-- zero steps to reach B[1]
for i = 1 to n-1 <-- Each step updates possible jumps from A[i]
for j = 1 to A[i] <-- Possible jump sizes are 1, 2, ..., A[i]
if i+j > n <-- Array boundary check
break
if B[i+j] > B[i]+1 <-- If this path to B[i+j] was shorter than previous
B[i+j] = B[i]+1 <-- Keep the shortest path value
C[i+j] = i <-- Keep the path itself
所需的跳跃次数为B[n]
。需要采取的路径是:
1 -> C[1] -> C[C[1]] -> C[C[C[1]]] -> ... -> n
可以通过简单的循环恢复。
该算法具有O(min(k,n)*n)
时间复杂度和O(n)
空间复杂度。 n
是A
中元素的数量,k
是数组中的最大值。
我保留了这个答案,但是cheeken的贪婪算法是正确的,效率更高。
答案 2 :(得分:5)
从数组构造有向图。例如:i-&gt; j if | i-j |&lt; = x [i](基本上,如果你可以在一跳中从i移动到j,则i-> j作为图中的边缘)。现在,找到从第一个节点到最后一个节点的最短路径。
FWIW,您可以使用Dijkstra的算法,以便找到最短的路线。复杂度为O(| E | + | V | log | V |)。自| E | &LT; n ^ 2,这变为O(n ^ 2)。
答案 3 :(得分:0)
从左(结束)开始..并且遍历直到数字与索引相同,使用这些数字的最大值。例如,如果列表是
list: 2738|4|6927
index: 0123|4|5678
一旦你从这个数字重复上述步骤,直到你达到最右边。
273846927
000001234
如果您没有找到与索引匹配的nething,请使用最远索引且值大于index的数字。在这种情况下7.(因为很快索引将大于数字,你可能只计算9个索引)
答案 4 :(得分:0)
基本理念:
通过查找所有可以从中跳转到目标元素的所有数组元素开始构建从结尾到开始的路径(所有i
使A[i] >= target - i
)。
将每个此类i
视为新目标并找到它的路径(递归)。
选择找到的最小长度路径,附加target
,返回。
python中的简单示例:
ls1 = [2,3,1,1,4]
ls2 = [4,11,1,1,1,1,1,1,1,1,1,1,1]
# finds the shortest path in ls to the target index tgti
def find_path(ls,tgti):
# if the target is the first element in the array, return it's index.
if tgti<= 0:
return [0]
# for each 0 <= i < tgti, if it it possible to reach
# tgti from i (ls[i] <= >= tgti-i) then find the path to i
sub_paths = [find_path(ls,i) for i in range(tgti-1,-1,-1) if ls[i] >= tgti-i]
# find the minimum length path in sub_paths
min_res = sub_paths[0]
for p in sub_paths:
if len(p) < len(min_res):
min_res = p
# add current target to the chosen path
min_res.append(tgti)
return min_res
print find_path(ls1,len(ls1)-1)
print find_path(ls2,len(ls2)-1)
>>>[0, 1, 4]
>>>[0, 1, 12]
答案 5 :(得分:0)
我们可以计算出远索引以跳到最大值,并且如果任意索引值大于远索引,我们将更新远索引值。
简单的O(n)时间复杂度解决方案
Instance member 'base' cannot be used on type 'Reactive<Base>'