在O(nlogn)中找到两组中的匹配对

时间:2013-10-30 07:48:37

标签: algorithm sorting complexity-theory

有一套A和B的大小为n,对于A组中的每张卡,B组中都有一张相应的卡。

描述一种更有效的算法,其平均案例复杂度为O(nlogn)测试,以找到匹配对。证明您的算法满足所需的复杂性。

我认为我可以使用quicksort对每个集合进行排序,即nlogn + nlogn,然后我会知道每个集合中的相应位置是匹配对。这是对的吗?这是整个问题

每组由n张卡组成,并且对于集合A中的每张卡,在集合B中存在属于同一帐户的相应卡,并且我们将这两张卡称为匹配对。每张卡都是一个小塑料物体,包含一个带有一些加密号码的磁条,对应于银行中的一个独特帐户。需要找到所有匹配对。有一种读卡器,当两个卡,一组来自A组,一组来自B组,插入机器时,其三个指示灯中的一个打开;如果对匹配则为绿色,如果A上的帐号大于B,则为红色;如果B上的数字高于A,则为黄色。但是,读卡器无法比较属于同一组的两张卡。

2 个答案:

答案 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

  

在快速排序中,有一个称为分区的子过程,可以在线性时间内将列表(从左到右的索引)分为两部分,一部分小于某个元素,哪些大于或等于元素。

考虑以下算法。

  1. 从A组中挑选任何一张牌。我们称之为 1
  2. 使用读卡器将B分区设置在它周围,这样它就可以将B组分成3个子集,等于卡a 1 ,小于卡a 1 ,和那些大于卡 1
  3. 只有一张卡等于卡 1 。我们将此卡称为b 1
  4. 将卡片b 1 插入“二叉搜索树”类型的东西及其配对卡a 1
  5. 从集合A中选择另一张卡片,将其称为 2
  6. 使用读卡器将其与b1进行比较,如果它小于b 1 ,则在步骤(2)的子集上运行分区,其中b k &lt;一个<子> 1 。如果它大于b 1 ,则在步骤(2)的子集上运行分区,其中b k &gt;一个<子> 2 。这是O(n / 2),因为我们在较小的集合上运行分区。
  7. 从集合B中取卡,等于 2 ,将其称为b 2 ,并将其插入到步骤(4)的二叉树中(通过比较插入)以前匹配来自集合A)的项目。
  8. 重复 3 4 ,依此类推,继续将B组分解为越来越小的集合,并使用二叉​​搜索树查找“更正“分区集以搜索 k in。
  9. 最终你会得到一个时间复杂度,如O(n)+ 2 * O(n / 2)+ 2 * O(n / 4)+ 2 * O(n / 8)等。打破问题就像这在每个正确的配对上使用二叉搜索树,我相信时间复杂度将是O(n log n)。在最坏的情况下,它显然是O(n ^ 2)就像快速排序一样。

    最终,您将得到一个已排序的二叉树,其中每个节点都包含一对匹配的卡。