看起来你想要一个O(n)合并,就像他们使用合并排序一样。我想我可能有一些坏消息要告诉你。我将(希望)证明,对于广义问题,你不能比O(nlog(n))做得更好:(因此,你应该只使用其他人提出的任何最优O(nlog(n))解决方案)。首先,我将从直觉开始,解释为什么会这样,然后我会写一个非正式的证明。
直觉
这个想法是将列表排序的问题变成你的问题,并表明如果你能比O(nlog(n)更快地解决你的问题,那么我可以比O(nlog(n))更快地对任何列表进行排序,我们知道这是错误的。我们将只使用整数来保持简单。
假设您有一些奇怪的序列要排序:.我现在将构建两个列表 Dec 和 Inc。我从(即)开始。然后,如果是增加,我从12月的值中减去1,并在Inc中计算必要的值,以求和为。如果是一个减少,那么我在 Inc 中的值加上 1,并在 Dec 中计算必要的值,以求和为 。我们将此算法应用于下表中的序列:X = 1, 3, 2, -10, 5, 4, 7, 25
1 = 1 + 0
x_1 = x_1 + 0
x_{i-1} -> x_i
x_i
x_{i-1} -> x_i
x_i
idx x Dec Inc
----------------------
1 | 1 = 1 + 0
2 | 3 = 0 + 3
3 | 2 = -2 + 4
4 | -10 = -15 + 5
5 | 5 = -16 + 21
6 | 4 = -18 + 22
7 | 7 = -19 + 23
8 | 25 = -20 + 45
请注意,我可以在O(n)中从排序转换为您的问题 - 注意:在O(n)时间内反向Inc以获得两个递减序列。然后,我们可以输入您的问题
A = {(1, 1), (2, 0), (3, -2), (4, -15), (5, -16), (6, -18), (7, -19), (8, -20)}
B = {(8, 45), (7, 23), (6, 22), (5, 21), (4, 5), (3, 4), (2, 3), (1, 0)}
现在,如果您可以将A和B按其值的总和(有序对中的第二个元素)组合成排序顺序,并得到类似的东西
C = {(8, 25), (7, 7), (5, 5), (6, 4), (2, 3), (3, 2), (1, 1), (4, -10)
那么你基本上已经完成了初始序列的argsort(按索引排序)。因此,如果你比O(nlog(n)更快地解决你的问题,那么我可以通过首先解决你的问题,然后将解决方案转换为我的列表排序问题来比O(nlog(n))更快地排序。特别是,我将使用复杂性O(n)+ O(复杂性)进行排序以解决您的问题)x_i
有待证明的声明
让您的两个键值列表成为
A = [(ka_i, va_i) | i = 1..n]
B = [(kb_i, vb_i) | i = 1..m]
按值的降序排序。找不到组合列表
C = [(ka_i, va_i + va_j) | ka_i = kb_j]
比 O(nlog(n)) 时间快。
校样大纲
这个证明所做的唯一假设是,你不能比O(nlog(n))时间更快地对列表进行排序,并且这个证明将通过提供在O(n)时间内运行的减少来继续,从对任何任意列表进行排序到你的问题。
从本质上讲,我们将证明,如果我们比O(nlog(n)更快地解决您的问题,那么我们也可以比O(nlog(n))更快地对任何任意列表进行排序。我们已经知道不可能比nlog(n)更快地对列表进行排序,因此您所需的解决方案也一定是不可能的。
证明详情
为简单起见,我们将对整数列表进行排序。设为任何整数序列。我们现在将构建两个列表,Dec 和 Inc。S = x_1, x_2, ..., x_n
我们有三个约束:
- 公司正在严格增加
- 12月严格减少
- 在算法的迭代 i 上,
Inc[j] + Dec[j] = x_j for all j = 1..i-1
顾名思义,Dec将严格减少,Inc将严格增加。我们将保持不变性x_i = Dec[i] + Inc[i] for i = 1..n
以下是减少:
# (Assume 1-indexed lists)
1. Initialize Inc = [x_1] and Dec = [0]
2. For i = 2..n:
a. if x[i] > x[i-1] then
Dec.append(Dec[i-1] - 1)
Inc.append(x_i - Dec[i])
else # We must have x[i] <= x[i-1]
Inc.append(Inc[i-1] + 1)
Dec.append(x_i - Inc[i])
3. Create list A and B:
A = [(i, Dec[i]) | i = 1..n]
B = [(i, Inc[i]) | i = 1..n]
4. B = reverse(B) # Reverse B because B was in increasing order and we
# need both lists to be in decreasing order
5. A and B are inputs to your algorithm.
If your algorithm can combine A and B into sorted order,
then we have also sorted S (via argsort on the keys).
您可能还渴望得到一个证据,证明我选择将Inc增加1或将12月减少1的临时方法有效。好吧,这是一个非正式的“证明”(你可以通过使用归纳法将其形式化):
Case x_{i} > x_{i-1}
回想一下,在本例中,我们选择将 Dec 递减 1。我们得到了这一点,我们知道.我们也可以说.x_{i} > x_{i-1}
Dec_{i-1} + Inc_{i-1} = x_{i-1}
(Dec_{i-1} - 1) + (Inc_{i+1} + 1) = x_{i-1}
既然 ,我们必须有 .因此。因此,如果我们只将 Dec 递减 1,我们将被迫向 Inc 添加至少 1,因此 Inc 仍然严格增加。x_{i} > x_{i-1}
x_{i} >= x_{i-1} + 1
x_{i} >= (Dec_{i-1} - 1) + (Inc_{i+1} + 1)
Case x_{i} ≤ x_{i-1}
回想一下,在本例中,我们选择将 Inc 递增 1。我们得到了这一点,我们知道.我们也可以说,既然,那一定是这样的。因此,如果我们向 Inc 添加 1,我们确信必须从 12 月中减去至少 1。x_{i} <= x_{i-1}
Dec_{i-1} + Inc_{i-1} = x_{i-1}
(Dec_{i-1} - 1) + (Inc_{i+1} + 1) = x_{i-1}
x_{i} <= x_{i-1}
(Dec_{i-1} - 1) + (Inc_{i+1} + 1) <= x_{i}
结论
您的问题无法比O(nlog(n)更快地完成。您最好只是组合成一个HashMap,然后在O(nlog(n))中对其元素进行排序,因为不可能找到更快的解决方案。
但是,如果您发现减少的问题或有疑问,请随时发表评论。我很确定这是正确的。当然,如果我错误地认为排序速度不比O(nlog(n)快),那么整个证明就崩溃了,但是最后我检查了一下,有人已经证明了O(nlog(n))是排序的最快复杂性。如果您更喜欢正式的减少,请发表评论。对我来说,现在已经很晚了,我跳过了一些“形式化”,但是当我有机会时,我可以编辑它们。
如果您编写用于创建约简的算法,则可以更好地理解。
另外:如果你想解释排序的O(nlog(n))绑定排序,请参阅这篇文章 排序算法的“Ω(n log n)障碍”的规则是什么?