我正在考虑针对一个问题的不同解决方案。假设我们有K个已排序的链表,我们将它们合并为一个。所有这些列表一起有N个元素。
众所周知的解决方案是使用每个列表中的优先级队列和弹出/推送第一个元素,我可以理解为什么需要O(N log K)
时间。
但是让我们来看看另一种方法。假设我们有一些MERGE_LISTS(LIST1, LIST2)
过程,它合并了两个排序列表,它需要O(T1 + T2)
时间,其中T1
和T2
代表LIST1
和{{1 }} sizes。
我们现在所做的通常意味着将这些列表配对并将它们逐对合并(如果数字是奇数,则最后一个列表,例如,可以在第一步中忽略)。这通常意味着我们必须制作合并操作的以下“树”:
LIST2
代表N1, N2, N3...
尺寸
LIST1, LIST2, LIST3
O(N1 + N2) + O(N3 + N4) + O(N5 + N6) + ...
O(N1 + N2 + N3 + N4) + O(N5 + N6 + N7 + N8) + ...
很明显,这些行中会O(N1 + N2 + N3 + N4 + .... + NK)
,每个行都会执行log(K)
次操作,因此O(N)
操作的时间实际上等于MERGE(LIST1, LIST2, ... , LISTK)
的
我的朋友告诉我(两天前)需要O(N log K)
时间。所以,问题是 - 我是否曾在某处或者他真的错了?如果我是对的,为什么不能使用这种“分而治之”的方法而不是优先队列方法呢?
答案 0 :(得分:3)
根据您的描述,听起来您的过程确实是O(N log K)。它也可以使用,所以你可以使用它。
我个人会使用带优先级队列的第一个版本,因为我怀疑它会更快。它在粗糙的大O意义上并不快,但我认为如果你实际计算出两者的比较和存储数量,第二个版本将需要多倍的工作。
答案 1 :(得分:3)
如果要合并少量列表,这种成对方案可能比优先级队列方法更快,因为每个合并的操作极少:基本上只有一个比较和每个项目的两个指针重新分配(转换为一个新的单链表)。如您所示,O(N log K)
(log K
步骤处理每个N
个项目。
但我认为,最佳优先级队列算法是O(sqrt(log K))
或O(log log U)
用于插入和删除(其中U
是可能的不同优先级的数量) - 如果您可以优先排序使用值而不必使用比较 - 所以如果你要合并可以给出的项目,例如整数优先级,K
很大,那么你最好使用优先级队列。
答案 2 :(得分:1)
这是O(2*log(K)*N)
这是O(N*log(K))
,因为您只2N
次添加O(log(K))
中的优先级队列,所以您的复杂性最差。
或者您可以将所有元素推送到O(2N)
中的向量中。并在O(2n*log(2n))
中对其进行排序。然后你有O(2N+2N*Log(2N))
,这是O(N*LOG(N))
,非常K = N
;
答案 3 :(得分:0)
它确实在O(N*log K)
中运行,但不要忘记,O(N*log K)
是O(N*K)
的子集。即你的朋友也没错。