【问题标题】:Algorithm for seeing if many different arrays are subsets of another one?查看许多不同数组是否是另一个数组的子集的算法?
【发布时间】:2017-04-30 09:17:00
【问题描述】:

假设我有一个约 20-100 个整数的数组,例如 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9](实际上数字更像 [106511349 , 173316561, ...],所有非负 64 位整数都在 2^63 以下,但出于演示目的,让我们使用这些)。

还有许多(约 50,000)个较小的数组,通常包含 1-20 个术语来匹配或不匹配:

1=[2, 3, 8, 20]
2=[2, 3, NOT 8]
3=[2, 8, NOT 16]
4=[2, 8, NOT 16] (there will be duplicates with different list IDs)

我需要找出其中哪些是正在测试的数组的子集。匹配列表必须包含所有正匹配,并且没有负匹配。所以对于这个小例子,我需要返回[3, 4] 之类的东西。列表 1 无法匹配,因为它需要 20,而列表 2 无法匹配,因为它没有 8。在这些情况下,可以通过使用高位/使数字为负数来轻松表示 NOT。

我需要以每秒 10,000 次的速度快速执行此操作。小数组是“固定的”(它们很少更改,比如每隔几秒一次),而大数组是针对每个要扫描的数据项完成的(因此每秒有 10,000 个不同的大数组)。

这已经成为一个瓶颈,所以我正在寻找优化它的方法。

我不确定最好的数据结构或表示这一点的方法。一种解决方案是转过头来看看我们甚至需要考虑哪些小清单:

2=[1, 2, 3, 4]
3=[1, 2]
8=[1, 2, 3, 4]
16=[3, 4]
20=[1]

然后我们会建立一个列表来检查,并对这些列表进行完整的子集匹配。但是,某些术语(通常是更频繁的术语)最终会出现在许多列表中,因此这里并没有太大的实际意义。

我想知道是否有人知道解决此类问题的更好算法?

【问题讨论】:

    标签: algorithm performance data-structures language-agnostic subset


    【解决方案1】:

    您可以尝试用较小的数组创建一棵树,因为它们的更改频率较低,这样每个子树都会尝试将剩余的小数组数量减半。

    例如,对较小数组中的数字进行频率分析。找出最接近一半较小数组的数字。使其成为树中的第一个检查。在您的示例中,这将是“3”,因为它出现在一半的小数组中。现在这是树中的头节点。现在将所有包含 3 的小列表放入左子树,将所有其他列表放入右子树。现在在每个子树上递归地重复这个过程。然后当一个大数组进来时,反向索引它,然后遍历子树得到列表。

    【讨论】:

    • 构建一棵树是有意义的,但我认为它需要是一棵三叉树:一个子树将包含指定3 的数组,一个子树将包含指定NOT 3 的数组,还有一个子树将包含未指定的数组。在每个分支,您需要下降到三个子树中的两个。最佳树结构可能是未指定任一子树最小的树结构,因为这是您必须无条件进入的子树。
    • “not 3”也可以是“3”节点的独立节点。
    • 没错,但我的主要观点是您将总是递归到“不需要这个”子树;所以你的“每个子树都试图将剩下的小数组数量减半”的目标并不理想。相反,您的目标应该是选择在不满足的情况下尽可能多地消除小数组的条件。
    • 好点,多个分支。我想可以在小型阵列上使用各种测试。因此,“给定一个小数组列表,哪个测试最有可能将我们必须继续查看的小数组的数量分成两半”的贪心算法,不断分裂,用一组小数组制作一棵树,可能是就易于编码和相当快的速度而言,物有所值。
    【解决方案2】:

    您没有说明您的哪些数组已排序 - 如果有的话。

    由于您的数据不是那么大,我会使用哈希映射来存储源集的条目(具有约 20-100 个整数的条目)。这基本上可以让您测试 O(1) 中是否存在整数。

    然后,考虑到 50,000(数组)* 20(每个术语)* 8(每个术语的字节数)= 8 兆字节 +(哈希映射开销),对于大多数系统来说,我会使用另一个哈希映射存储测试的数组。这样您就不必重新测试重复项。

    【讨论】:

      【解决方案3】:

      我意识到从 CS 的角度来看这可能不太令人满意,但如果您正在执行大量不相互影响的小任务,您可能需要考虑将它们并行化(多线程)。每秒 10,000 个任务,在每个任务中比较不同的数组,应该符合要求;您没有提供有关您正在做什么的任何细节(例如,所有这些数组的来源),但可以想象多线程可以大大提高您的吞吐量。

      【讨论】:

        【解决方案4】:

        首先,按照你的建议去做;从输入整数到它所在的过滤器数组的 ID 制作一个哈希图。这让您可以说“输入 #27 在这 400 个过滤器中”,然后将这 400 个过滤器放入排序集中。然后,您必须对每个排序集进行交集。

        可选:从每个输入整数到其在过滤器集中的频率创建第二个哈希图。当输入进入时,使用第二个哈希图对其进行排序。然后取最不常见的输入整数并从它开始,这样你在每个步骤上要做的整体工作就更少了。还要计算“非”情况的频率,因此您基本上可以在每一步中获得最大的收益。

        最后:这很容易变成一个并行编程问题;如果它在一台机器上不够快,那么如果它返回的任何内容都足够有用,您似乎可以很容易地在其上放置更多机器。

        【讨论】:

          猜你喜欢
          • 2010-09-24
          • 1970-01-01
          • 2012-05-20
          • 2012-08-29
          • 1970-01-01
          • 2016-12-13
          • 2021-07-10
          • 1970-01-01
          相关资源
          最近更新 更多