令我惊讶的是,我找不到关于此的论文-可能是搜索了错误的关键字。
因此,我们得到了一个数组,其中每个函数都有一个索引;f是一个排列。
我们如何根据对数组进行重新排序,使其内存和运行时间尽可能接近O (1 )和O (n )?
当此任务变得更容易时,是否还有其他条件?例如,当我们明确知道一个函数是f的逆时?
我知道一种算法,该算法遵循循环并为每个索引遍历一个循环以检查它是否在其循环中最小,但是同样,它具有最坏情况下的运行时间,尽管平均而言它似乎表现更好。 ..
令我惊讶的是,我找不到关于此的论文-可能是搜索了错误的关键字。
因此,我们得到了一个数组,其中每个函数都有一个索引;f是一个排列。
我们如何根据对数组进行重新排序,使其内存和运行时间尽可能接近O (1 )和O (n )?
当此任务变得更容易时,是否还有其他条件?例如,当我们明确知道一个函数是f的逆时?
我知道一种算法,该算法遵循循环并为每个索引遍历一个循环以检查它是否在其循环中最小,但是同样,它具有最坏情况下的运行时间,尽管平均而言它似乎表现更好。 ..
Answers:
选项0:Faith E. Fich,J。Ian Munro,Patricio V. Poblete O (n log n )时间O (log 2 n )空间的置换(1995)。
选项1:通过将排列压缩为简洁的数据结构来作弊,请参见Munro http://www.itu.dk/people/ssrao/icalp03-a.pdf。
选项2:使用素数周期分解来简洁地存储烫发,并使用多余的空间作弊http://oeis.org/A186202
选项3:跟踪每个循环的最大索引。对于每次迭代,请使用最大的看不见的索引将周期中的所有内容移动一个。如果它达到可见索引,则撤消所有工作,因为该循环已被操纵。时间,O (#个周期* log n )空间。
选项4:跟踪所操纵的每个循环的最大索引,但只能以不同的循环长度进行批量处理。对于每次迭代,请使用最大的看不见的索引将周期中的所有内容移动一个。如果达到可见索引,则撤消所有工作,因为该循环已被操纵。时间,Ô ((#周期_ 与_ 相同_ 尺寸)* 日志Ñ )空间。
选项5:Munro与选项0来自同一篇论文,对于如果i是该循环中最大的索引,则n旋转p (i )的循环。O (n 2)时间和O (log n )空间。
如果使用置换的循环表示形式,则需要1个额外的数组元素来存储当前置换的项目,并且可以以更差的O(N)操作来运行循环。
可以使用N-1或更少的交换将N个项目的任何排列转换为任何其他排列。此方法最坏的情况可能要求对您的oracle F()进行O(n ^ 2)次调用。从最小的位置开始。令x为我们当前交换的头寸。
如果F(x)> = x,则交换位置x和F(x)。否则,我们必须找到位置F(x)中的项目当前在列表中的位置。我们可以通过以下迭代来做到这一点。令y = F(x)。执行直到y> = x:y = F(y):结束执行。现在交换位置x和y。
此方法使用F的倒数,需要n位存储空间。如果x是项目在原始数组中的位置,则让G(x)是项目在排序数组中的位置。令B为n位数组。将B的所有n位设置为0。
对于x = 1到n-1:如果B(x)== 0然后:y = G(x):直到x == y:交换位置x和y:B(y)= 1:y = G( y):循环:ENDIF:下一个X
此方法会一直将当前在位置x的项目交换为项目的最终位置。当正确的项目交换到位置x时,内部循环结束。由于每次交换都将至少一个项目移动到项目的最终位置,因此内部Do循环在运行期间执行的次数不能超过n-1次。我认为这种方法是O(n)的时间和空间。