从正数的数组A开始。从索引i开始,你可以移动索引i + x得到任何x< = A [i]。目标是找到到达阵列末尾所需的最小移动次数。
以下是一个例子:
{ 2 , 4 , 1 , 2 , 3 , 2 , 4 , 2}
如果你在每次行动中总是尽可能地走,那么这就是你得到的:
0 , 2 , 3 , 5 , 7
这需要4步。但是你可以通过这种方式更快地完成它
0 , 1 , 4 , 7
这只需要3个动作。
我想到了这一点并做了我想到的第一件事,但在思考了几天之后,我仍然不知道如何做得更好。
这是我的想法。从数组的末尾开始,跟踪从某个位置到结尾的最小移动次数。所以对于这个例子,moves[7] = 0
因为它已经结束了。然后moves[6] = 1
,因为它需要一个动作才能结束。我的公式是
moves[i] = 1 + min(moves[i+1], moves[i+2], ... , moves[i+A[i]])
当我开始时,我知道移动的次数。
所以这是O(n ^ 2)我觉得没问题,但可能还有更快的方法吗?
答案 0 :(得分:13)
既然您可以选择[1,A [i]]中的任何x,我想有一个非常简单的解决方案:
从0开始:
选择下一个可到达的元素,您可以从该元素到达更远的元素。 即选择i在[1,A [i]]
中最大化i + A [i + x]直到你到达列表的末尾。
示例:强>
{2,4,1,2,3,2,4,2}
从0开始
从0开始,你可以得到1或2:
因此max(0 + A [0 + x])适用于i = 1
选择1 从1你可以到2 3 4:
因此max(1 + A [1 + x])适用于i = 4
选择4
你可以达到7
停止
the resulting list is :
0,1,4,7
正如我在评论中所解释的那样,我认为它是O(N),因为从i开始,你至少在2 * x的操作中达到i + x + 1。
'伪'证明
你从0开始(这是最佳的)
然后你选择i最大化(0 + A [0 + x])(即最大化下一个元素的可达性)
从那个i你可以到达任何其他元素,这些元素可以从0到达的所有其他元素到达(这是一个很长的句子,但它意味着:谁可以做得更多,可以做得更少,因此,如果我不是最优的,那就是好最好)
所以我是最优的
然后逐步推导出这种推理,证明了该方法的最优性。
如果有人知道如何以数学方式表达,请随时更新。
答案 1 :(得分:4)
将数字数组视为图形,然后问题等同于Shortest Path Problem,可以使用Dijkstra's algorithm在O(|E|+|V|log|V|)
时间内解决。
E = ∑
的数字。
V =数字#。
答案 2 :(得分:2)
使用您的基本想法,但从头开始,您可以获得O(n)
。
目标是制作一个序列(A_i1, A_i2, ..., A_ik, ...)
,以便
位置0,1,2,...,ik
可以k
或更少步骤
位置i(k-1)+1, i(k-1)+2, ..., ik
无法在少于k
步骤中达到
基本案例很简单:
i0 = 0
i1 = A[0]
和归纳部分并不太复杂:
i(k+2) = max { A_(ik+1) + ik , A_(ik+1) + ik+1, ..., A_(i(k+1)) + i(k+1) }
答案 3 :(得分:2)
我会反对这个流程并告诉你你的算法是“完美的”。
它以最干净的形式使用dynamic programming,其复杂性并不是那么糟糕。从这个意义上讲,我会说这可能是你在面试中所期待的。
如果您对条目有界(例如A [i]< = C(N)),则其复杂度为O(N * max(C(N),N))。例如,如果所有条目都小于K,则为O(N)。
使用Dijkstra的算法(或者更普遍地将问题简化为最短路径问题)是明智的,但我将其排在干净的DP解决方案之后,因为图算法很复杂(如果你被问及有关,它可能适得其反它们)。
注意Dijkstra将改为O(N C(N)+ N log N)(N个顶点和N C(N)个边缘)。因此,根据C,您要么在复杂性方面要么严格要求也要相同。
答案 4 :(得分:1)
您可以将其表示为图算法(实际上,问题不能是什么?)。让数组中的位置为顶点,并且可能的目标从每个顶点开始具有边。在您的示例中,顶点0的边缘为1和2,而顶点1的边缘为2,3,4和5.
有几种有效的图搜索算法。例如,Dijkstra是O(|E| + |V|log|V|)
,而A *是O(log h*)
,如果你能想出一个好的启发式,那就更好了。
答案 5 :(得分:0)
动态编程解决方案:
跟踪每个元素您可以到达的最小步骤数以及您来自哪里。然后只需简单地遍历数组,并为每个元素更新可用的下一个位置(从i + 1到i + a [i])。
{ 2 , 4 , 1 , 2 , 3 , 2 , 4 , 2}
0
{ 2 , 4 , 1 , 2 , 3 , 2 , 4 , 2}
0 1 1 (num of steps)
0 0 (source)
^ (current position)
{ 2 , 4 , 1 , 2 , 3 , 2 , 4 , 2}
0 1 1 2 2 2
0 0 1 1 1
^
{ 2 , 4 , 1 , 2 , 3 , 2 , 4 , 2}
0 1 1 2 2 2
^
etc...
这是O(n + sum(a [i]))..或者稍微少一点,你不必超出数组的边界。
答案 6 :(得分:0)
您可以将数组转换为图形并找到最短路径。以下是从数组到图形的转换应该如何工作。
每个数组元素都是一个节点。并且,基于数组元素中的值,我们可以跳转到节点与其他索引(节点)之间绘制的边。一旦我们得到这个图,我们就可以找到最短路径,这比O(n ^ 2)好。
答案 7 :(得分:0)
我的天真的方法 - 从一开始,通过所有路径先做呼吸(子节点是A [i + 1] .. A [i + n]),保存找到的路径你的某些数组,然后得到最短的路径。当然所有索引i + n>长度(A)被丢弃。所以它的上限是O(n * min(n,max(A [i = 0..n]))+ n) - 在实践中应该小于二次。
答案 8 :(得分:0)
以下是Ricky Bobby答案的略微修改,我将证明这是最佳的:
find_shortest_path(A):
path := [0]
last := 0
max_reachable = 0
while A[last] + last < length(A) :
next_hop := x such that max_reachable < x <= A[last] + last and last + A[x] is maximum
push(path, x)
max_reachable = A[last] + last
last := x
return path
正确性证明: 我将使用归纳我的算法创建的路径的节点。
我要显示的属性是P(i)=我路径的第i个节点的“到达”不小于任何最佳路径的第i个节点
其中,覆盖范围定义为可以从该节点跳转到的最高节点数,如果可以超出数组末尾,则为+无穷大
P(0)很明显。
假设对于k> = 0
,P(k)为真现在考虑我的算法创建的路径中的第(k + 1)个节点。由于我的算法选择节点k使其至少具有与最优路径节点k相同的范围,因此可能是我的算法的第(k + 1)节点的节点集是同一个节点的超集。任何最佳路径。由于我的算法选择具有最大范围的节点,因此P(K + 1)为真。
通过归纳,P(k)对于所有k都是正确的(直到创建的路径的大小)。
因为我的算法会在数组结束时立即结束,并且这不会晚于任何最佳路径,因此我的算法创建的路径是最佳的。
最优性证明: 数组的每个单元最多被考虑一次,因此它是O(n),它是渐近最优的。我不认为设计一种算法可以在每种情况下检查更少的单元格。
答案 9 :(得分:0)
我的方法:
创建一个数组reqSteps来存储输入转义所需的移动次数
从数组的末尾开始。
检查input [i]是否可以自行转义数组,如果是,则在minSteps中输入1,如果不是,则存储连续输入[i]值+ 1的最小值。
结果是minSteps [0];
top方法不适用于输入{10,3,1,1,1,1,1,1,1,1,2,1};
这将给出9作为答案
正确答案是2.
public static void arrayHop()
{
int[] input = { 10, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1 };
int length = input.length;
int answer = calcArrayHop(input, length);
}
public static int calcArrayHop(int[] input, int length) {
int minSteps;
int[] reqSteps = new int[length];
for(int i=0;i<length;i++)
reqSteps[i]=Integer.MAX_VALUE;
int nextStep;
for (int i = length - 1; i >= 0; i--) {
int minsteps = Integer.MAX_VALUE;
if (i + input[i] >= length) {
reqSteps[i] = 1;
} else
{
for (int j = i+1; j <= (i + input[i]); j++) {
if(j>input.length-1)
break;
if (reqSteps[j] < minsteps)
minsteps = reqSteps[j];
}
reqSteps[i] = minsteps+1;
}
}
return reqSteps[0];
}
}