假设我有两个长度相同的n
数组,分别命名为A
和B
。
这两个数组包含实数值。 我们将两个数组之间的距离定义为均方距离。
dist(A,B) = sqrt( sum((A - B)2) )
我想找到A
的排列,它给出到B
的最小距离。
天真的方法是尝试A
的每个排列并记录最小距离。但是,该方法的复杂度为O(n!)。
是否有一种算法的复杂度小于O(n!)?
答案 0 :(得分:40)
您可以同时对A和B进行排序。在这种情况下,欧几里得距离很小。
如果B必须保持固定,那么您只需要反转排序B所需的排列并将其应用于A的排序版本。
此解决方案确实假定您只想查找一个排列,而不是最简单的排列(因为通过排列进行排序和取消排序将不会非常有效)。
证明: 令S,T为我们的一对数组。 我们可以假设S被排序而不失一般性,因为所有这些 重要的是两组元素之间的映射。
让T为使两个数组之间的距离最小的排列, 并以d为该距离。
假设T不是 排序的。然后存在元素i,js.t。 T_i> T_j
S_i + k1 = S_j
T_i = T_j + k2
where k1,k2 > 0
让x为除i和j之外的所有元素的总距离。
d = x + (S_i - T_i)^2 + ((S_i + k1) - (T_i - k2))^2
如果我们交换T_i和T_j的顺序,那么我们的新距离是:
d' = x + (S_i - (T_i - k2))^2 + ((S_i + k1) - T_i)^2
因此: d-d'= 2 * k1 * k2,这与我们的假设T等于使距离最小的排列相矛盾,因此必须对排列进行排序。
可以使用多种方法在O(n log n)中对两个数组进行排序。
答案 1 :(得分:34)
您描述的问题等同于Minimum Cost Perfect Matching Problem,可以使用The Hungarian Algorithm有效(准确)解决。在“最小成本完美匹配问题”中,您有一个输入加权二分图,其中两组具有相同的大小n,每个边的成本均为非负数。目标是找到最低成本的完美匹配。
在您的情况下,二部图是biclique。也就是说,一组中的每个顶点都连接到另一组中的每个顶点,并且边(i,j)
的代价为(A[i] - B[i])^2
(其中i
对应于中的索引i
数组A和j
对应于数组B中的索引j
。
编辑: 这不是解决该问题的最佳方法。 Ivo Merchiers在效率和简便性方面都提出了a better solution。我之所以不删除答案,是因为我提出的解决方案对于不适用Ivo解决方案的距离度量非常有价值(因为他的方法通过利用欧几里德距离的性质而起作用)。
答案 2 :(得分:10)
您可以对 A 和 B 进行排序,然后匹配相应的元素。
想象一下,有 A , Ai 和 Aj 两个元素,分别与 Bi 和 Bj 。
这些匹配项的错误贡献为:
(Ai-Bi)^ 2 +(Aj-Bj)^ 2
= Ai ^ 2 + Bi ^ 2 + Aj ^ 2 + Bj ^ 2-2(AiBi + AjBj)
交换比赛还是让比赛保持原样更好?
好吧,如果我们交换它们,错误的区别是:
2(AiBi + AjBj)-2(AiBj + AjBi)
〜AiBi-AiBj + AjBj-AjBi
= Ai(Bi-Bj)-Aj(Bi-Bj)
=(Ai-Aj)(Bi-Bj)
因此,如果 A 和 B 的顺序相同,则该乘积为正,并且如果交换它们,该错误将上升。如果它们的顺序不同,则该乘积为负,如果您交换它们,该错误将消失。
如果您反复交换任何乱序的货币对,直到没有这样的货币对,您的错误就会不断减少,最终您将排在第 n 个在整个数组中,A 与 n 个最大的 B 相匹配。
仅对它们进行排序和匹配是最佳的,当然,它比匈牙利算法要快。
答案 3 :(得分:6)
根据向量构造二部图。在此图中找到最小的重量完美匹配。
如何构造图形。
A
,B
是图的两个部分。每个节点都有n
个节点。i
中的A
连接到j
中的B
,并使其重心为abs(A[i] - B[j])
。 我相信可以在O(n^2)
中完成。
请参见http://www.cse.iitd.ernet.in/~naveen/courses/CSL851/lec4.pdf
如果A
中的每个数字在B
中只有一个最接近的数字,那么您可以在O(n \log n)
中进行此操作。因为您有实数,所以可能是这种情况。
如何?
O(n \log n)
O(n \log n)
。 如果这些数字来自真实世界,并且甚至具有一些随机性,那么每对数字之间的差异可能是唯一的。您可以通过对输入向量进行实验来验证是否是这种情况。然后问题就容易解决了!
答案 4 :(得分:0)
我在python中需要此功能,因此我将根据Ivo Merchiers的回答在这里分享我的解决方案:
target = [12, 14, 4512, 123, 4412]
source = [12, 14, 120, 4413, 5512]
permutationToSortTarget = [i[0] for i in sorted(enumerate(target), key=lambda x: x[1])] # get permutation that would sort target
permutationNeeded = [i[0] for i in sorted(enumerate(permutationToSortTarget), key=lambda x: x[1])] # get needed permutation
source.sort()
source = [source[i] for i in permutationNeeded] # apply permutation to sorted source