【发布时间】:2011-10-12 15:50:21
【问题描述】:
我有两组整数A 和B(A 的大小小于或等于B),我想回答这个问题,“A 与@987654327 有多接近@?”。我想回答这个问题的方法是衡量你必须从A 中的给定a 到在B 中找到b 的距离。
我想产生的具体措施如下:对于每个a,找到最接近的b,唯一的问题是一旦我将b与a匹配,我就不能再使用b 与任何其他 a 匹配。 (编辑:我尝试实现的算法总是更喜欢较短的匹配。因此,如果b 是多个a 的最近邻居,请选择最接近b 的a。我不是确定如果多个a 与b 的距离相同,该怎么办,现在我选择a 之前的b,但这很随意,不一定是最佳的。) 'll for make these sets, 最终产品,是一个直方图,在垂直轴上显示对数,在 x 轴上显示对的距离。
所以如果A = {1, 3, 4} 和B = {1, 5, 6, 7},我将得到以下a,b 对:1,1、4,5、3,6。对于这些数据,直方图应显示距离为零的一对、距离为 1 的一对和距离为 3 的一对。
(这些集合的实际大小的上限约为 100,000 个元素,我从已从低到高排序的磁盘中读取它们。整数范围从 1 到 ~20,000,000。编辑:另外,A 的元素和B 是唯一的,即没有重复的元素。)
我想出的解决方案有点笨拙。我正在使用 Perl,但问题或多或少与语言无关。
-
1234563例如
-
接下来,我遍历
李>A以查找出现在A和B中的所有哈希元素,将它们标记在度量中,然后将它们从哈希中删除。 然后,我对所有哈希键进行排序,并使哈希的每个元素指向其最近的邻居,就像一个链表,其中给定的哈希元素现在看起来像
$hash{6} = {b=>1, previous=>4, next=>8}。链表不知道下一个和上一个元素是在A还是B。然后我循环从
d=1开始的对距离,并找到距离为d的所有对,标记它们,从哈希中删除它们,直到没有更多A的元素可以匹配。
$hash{5} = {a=>1, b=>1} 如果数字 5 出现在两个数据集中。 (如果它只出现在A 中,您将拥有$hash{5} = {a=>1}。)
循环如下所示:
for ($d=1; @a > 0; $d++) {
@left = ();
foreach $a in @a {
$next = $a;
# find closest b ahead of $a, stop searching if you pass $d
while (exists $hash{$next}{next} && $next - $a < $d) {
$next = $hash{$next}{next};
}
if ($next is in B && $next - $a == $d) {
# found a pair at distance $d
mark_in_measure($a, $next);
remove_from_linked_list($next);
remove_from_linked_list($a);
next;
}
# do same thing looking behind $a
$prev = $a;
...
# you didn't find a match for $a
push @left, $a;
}
@a = @left;
}
这个循环显然更喜欢匹配b's 的对,它们出现得比a's 晚;我不知道是否有一种明智的方法来决定以后是否比以前更好(在获得更接近的配对方面更好)。我感兴趣的主要优化是处理时间。
【问题讨论】:
-
你说 A = {1, 3, 4}, B = {1, 5, 6, 7},你得到 a,b 对 1,1, 4,5, 3, 6,即距离 0、1、3 各一对。1,1,3,5,4,6 距离 0,2,2 的对决不是更好吗?
-
你用什么来计算匹配的费用?最小距离总和?距离平方和的最小值?
-
@jwpat7 我不确定它是否更好,因为对之间的总距离保持不变。可能构造
A和B是可能的,这样总是更喜欢较短的对会导致对距离的总和更高,尽管对我来说你将如何去做并不明显。即便如此,这个简单的贪心算法对于我的应用来说已经足够好了。如果优化不是很复杂,那么我会对你如何做到这一点感兴趣。 -
@missingno 成本函数方法会很有趣,但我可以接受总是更喜欢较短匹配的算法。
标签: algorithm language-agnostic nearest-neighbor