我有一个指针数组(这是算法,所以不要进入语言细节)。大多数情况下,此数组指向数组外部的位置,但它会降级到数组中的每个指针指向数组中的另一个指针的位置。最终,这些指针形成了一个无限循环。
因此,假设整个数组由指向数组中另一个位置的指针组成,并且从头开始,那么如何在时间和空间中找到效率最高的循环长度?我相信最好的时间效率是O(n),因为你必须遍历数组,最好的空间效率是O(1),虽然我不知道如何实现。
Index: 0 1 2 3 4 5 6
Value: *3 *2 *5 *4 *1 *1 *D
D是循环开始之前指向的数据。在这个例子中,循环是1,2,5并且它无限重复,但是索引0,3和4不是循环的一部分。
答案 0 :(得分:4)
这是循环检测问题的一个实例。罗伯特·弗洛伊德于1960年发现了一种优雅的O(n)
时间O(1)
空间解决方案;它通常被称为"Tortoise and Hare"算法,因为它包括用两个指针遍历序列,一个指针移动速度是另一个指针的两倍。
这个想法很简单:对于某些k
,循环必须有一个长度为k
的循环。在每次迭代中,野兔移动两步并且乌龟移动一步,因此它们之间的距离比前一次迭代中的距离大一。因此,每k
次迭代,它们是彼此相距k
步的倍数,并且一旦它们都处于循环中(一旦乌龟到达就会发生),如果它们是...的倍数k
分开,他们都指向同一个元素。
如果您需要知道的是周期的长度,那么等待野兔和乌龟到达同一地点;然后你沿着循环步进,计算步数,直到你再次回到同一个地方。在最坏的情况下,总的步数将是尾部的长度加上循环长度的两倍,其长度必须小于元素数量的两倍。
注意: 编辑第二段可能会使这个想法“更加明显”,无论这意味着什么。一个正式的证据很简单,实现也是如此,所以我没有提供。
答案 1 :(得分:0)
正如你所描述的那样,数组变成了一个图形(更恰当地说是一个图形),其中每个顶点都具有正好一个的度数。这种图的组成部分只能由链组成,每个链可能以单个循环结束。也就是说,每个组件的形状都像O或类似6.(我假设没有指针为空,但这很容易处理。你最终得到的是1形组件,根本没有循环。)
您可以通过“访问”跟踪所有这些组件,并使用“已访问”哈希或标记数组跟踪您曾经去过的地方。
这是一个算法。
编辑它只是针对每个节点一个子节点的情况简化的forrest的DFS,这消除了对堆栈(或递归)的需要,因为不需要回溯。
Let A[0..N-1] be the array of pointers.
Let V[0..N-1] be an array of boolean "visited" flags, initially false.
Let C[0..N-1] be an array if integer counts, initially zero.
Let S[0..N-1] be an array of "step counts" for each component trace.
longest = 0 // length of longest cycle
for i in 0..N-1, increment C[j] if A[i] points to A[j]
for each k such that C[k] = 0
// No "in edges", so must be the start of a 6-shaped component
s = 0
while V[k] is false
V[k] = true
S[k] = s
s = s + 1
k index of the array location that A[k] points to
end
// Loop found. Length is s - S[k]
longest = max(longest, s - S[k])
end
// Rest of loops must be of the O variety
while there exists V[k] false
Let k be such that V[k] is false.
s = 0
while V[k] is false
V[k] = true
s = s + 1
k index of the array location that A[k] points to
end
// Found loop of length s
longest = max(longest, s)
end
空间和执行时间都与输入数组A
的大小成正比。如果您愿意两次跟踪6个形状的组件,则可以删除S
数组。
添加我完全同意,如果没有必要找到最大尺寸的周期,那么the ancient "two pointer" algorithm for finding cycles in a linked list 是优越的,因为它只需要恒定的空间。
答案 2 :(得分:0)
如果节点的元素指向其指向的节点的元素以及每个节点,则创建数组中元素的有向图,其中节点指向另一个节点。跟踪节点的indegree(指向它的指针的数量。)在创建图形时,如果存在具有indegree == 2的节点,则该节点是无限循环的一部分。
如果第一个元素包含在无限循环中,则上述操作失败,因此在算法开始之前,将1个indegree添加到第一个元素以解决此问题。