有一套A和B的大小为n,对于A组中的每张卡,B组中都有一张相应的卡。
描述一种更有效的算法,其平均案例复杂度为O(nlogn)测试,以找到匹配对。证明您的算法满足所需的复杂性。
我认为我可以使用quicksort对每个集合进行排序,即nlogn + nlogn,然后我会知道每个集合中的相应位置是匹配对。这是对的吗?这是整个问题
每组由n张卡组成,并且对于集合A中的每张卡,在集合B中存在属于同一帐户的相应卡,并且我们将这两张卡称为匹配对。每张卡都是一个小塑料物体,包含一个带有一些加密号码的磁条,对应于银行中的一个独特帐户。需要找到所有匹配对。有一种读卡器,当两个卡,一组来自A组,一组来自B组,插入机器时,其三个指示灯中的一个打开;如果对匹配则为绿色,如果A上的帐号大于B,则为红色;如果B上的数字高于A,则为黄色。但是,读卡器无法比较属于同一组的两张卡。
答案 0 :(得分:4)
您可以使用卡片形式A作为枢轴来快速选择B组。因此您可以通过这种方式实现快速排序。因此,从A组中选择一张卡,将B组划分为越来越小。如果您在B中找到匹配的卡,则可以使用此卡划分A组。如果你没有找到匹配卡重复。如果发现以与quicksort相同的方式将算法应用于越来越小的组。重复,直到找到所有匹配的卡片。复杂度与快速排序相同,因此在最坏情况下为O(n ^ 2),平均为O(NlogN)。
Erlang中的示例实现:
-module(abcards).
-export([find_pairs/2]).
find_pairs([], _) -> [];
find_pairs(_, []) -> [];
find_pairs([A|As], Bs) ->
case partitionB(A, Bs, [], [], not_found) of
{_, _, not_found} -> find_pairs(As, Bs);
{BLess, BMore, B} ->
{ALess, AMore} = partitionA(B, As, [], []),
[{A, B} | find_pairs(ALess, BLess) ++ find_pairs(AMore, BMore) ]
end.
card_reader(A, B) when A > B -> red;
card_reader(A, B) when A == B -> green;
card_reader(A, B) when A < B -> yellow.
partitionB(_, [], BLess, BMore, Found) -> {BLess, BMore, Found};
partitionB(A, [B|Bs], BLess, BMore, Found) ->
case card_reader(A, B) of
red -> partitionB(A, Bs, [B|BLess], BMore, Found);
green -> partitionB(A, Bs, BLess, BMore, B);
yellow -> partitionB(A, Bs, BLess, [B|BMore], Found)
end.
partitionA(_, [], ALess, AMore) -> {ALess, AMore};
partitionA(B, [A|As], ALess, AMore) ->
case card_reader(A, B) of
red -> partitionA(B, As, ALess, [A|AMore]);
yellow -> partitionA(B, As, [A|ALess], AMore)
end.
答案 1 :(得分:1)
我认为在这个问题上滥用分区是明智的。
来自Wikipedia:
在快速排序中,有一个称为分区的子过程,可以在线性时间内将列表(从左到右的索引)分为两部分,一部分小于某个元素,哪些大于或等于元素。
考虑以下算法。
最终你会得到一个时间复杂度,如O(n)+ 2 * O(n / 2)+ 2 * O(n / 4)+ 2 * O(n / 8)等。打破问题就像这在每个正确的配对上使用二叉搜索树,我相信时间复杂度将是O(n log n)。在最坏的情况下,它显然是O(n ^ 2)就像快速排序一样。
最终,您将得到一个已排序的二叉树,其中每个节点都包含一对匹配的卡。