使用两个队列反转列表


12

这个问题的灵感来自于一个现有的问题,即是否可以在每个堆栈操作的摊销时间中使用两个队列来模拟堆栈。答案似乎是未知的。这是一个更具体的问题,与特殊情况相对应,在特殊情况下,首先执行所有PUSH操作,然后执行所有POP操作。使用两个最初为空的队列如何有效地反转N个元素的列表?合法操作是:O(1)N

  1. 使输入列表中的下一个元素入队(到任一队列的尾部)。
  2. 将元素从任一队列的开头出队,然后再次入队(到任一队列的尾部)。
  3. 使任一队列开头的元素出队,并将其添加到输出列表。

如果输入列表包括元素,生成反向输出列表[ N N - 1 ,...所需的最小操作数是多少2 1 ]的行为?证明它比O N 增长快的证据将特别有趣,因为它将解决否定的原始问题。[1,2,...,N1,N][N,N1,...,2,1]O(N)


更新(2011年1月15日):问题可以在,如提交的答案和他们的评论中所示;Ω N 的下限很小。这些界限能否改善?O(NlogN)Ω(N)


澄清一下:通过“任一队列中的最后一个元素”,您是指队列开头的元素吗?
彼得·泰勒

@Peter:是的,谢谢您的澄清。我已经编辑了问题。
mjqxxxx 2011年

输入和输出列表都是堆栈吗?如果是这样,那么n个op1(到同一队列)后跟n个op3,是否相反?我想我一定错过了一些重要的东西。
jbapple 2011年

@jbapple:不,它们不是堆栈。您需要以与从输入列表中读取的相反顺序将元素写入输出列表。
mjqxxxx 2011年

Answers:


11

如果N是2的幂,我相信O(N log N)运算就足够了,即使对于一个稍微受限制的问题,在该问题中,所有项目都从一个队列中开始,并且必须以相反的顺序在一个队列中结束(无输入和输出列表)。

在O(N)步骤中,可以从一个队列中的所有元素开始,播放“一个为您一个为我一个”,以将它们拆分为另一个队列中的交替子集,然后将它们重新组合为一个队列。就物品位置的二进制表示而言,这实现了旋转操作。

在O(N)步骤中,还可以从一个队列中取出成对的元素,交换它们,然后放回它们,反转所有对。就项目位置的二进制表示而言,这补充了位置的低位。

通过重复O(log N)次非随机和成对交换,我们可以补充仓位的二进制表示形式的所有位-与反转列表相同。


然后,我认为您可以将列表分解为二进制表示形式,并逐个反向处理O(n lg n)算法。
jbapple

我当时以为可以通过使用2-3棵树而不是二进制树来扩展到所有N,但是也许您的想法更简单。但是,如何在O(n log n)个总步骤中反转每个O(log n)件?
David Eppstein

从0到[lg n]的时间为i的时间为O(sum(2 ^ i)lg(2 ^ i)),Wolfram alpha表示为O(n lg n):wolframalpha.com/input/?i=sum+ (2 ^ k)+ log2 +(2 ^ k)+ from + 0 + to + log2 + n
jbapple 2011年

当然,如果您可以按其长度乘以其对数的时间按比例反转每个片段,那么您就完成了。但是一旦您将它们反转,就必须将它们放置在某个位置,这可能会使反转剩余的部分更加困难。
David Eppstein

问题在于“输出列表”。我们可以把它们放在那里吗?
jbapple 2011年

1

i=0N/21(N2i2)

让我们将两个可用的队列命名为left和right。这是此算法的基本思想,并假设N为偶数:

  1. 从元素的初始列表中读取值,并将所有奇数推入左侧队列,将偶数推入右侧队列
  2. 第一步,最快的输出最大值的方法是将N / 2-1个元素从右边的队列转移到左边的队列中,然后将右边队列中的最高值弹出到输出列表中
  3. 现在我们必须对另一个队列执行相同的操作-将N / 2-1元素从左队列转移到右队列,然后将左队列中的顶部元素弹出到输出列表中
  4. 交换队列并为N = N-2重复步骤2和3。

很容易看出算法应如何处理奇数N。


您可以使用$ ... $插入类似LaTeX的代码(减去\)。
Mark Reitblatt 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.