【发布时间】:2012-03-10 07:40:18
【问题描述】:
问题
我得到了 N 个 C 布尔值数组。我想将它们组织成一个数据结构,使我能够尽可能快地执行以下操作:给定一个新数组,如果该数组是任何存储数组的“超集”,则返回 true。对于超集,我的意思是:如果 A[i] 对于 B[i] 为真的每个 i 都为真,则 A 是 B 的超集。如果 B[i] 为假,那么 A[i] 可以是任何东西。
或者,就集合而不是数组而言:
将 N 个集合(每个集合包含 C 个可能的元素)存储到一个数据结构中,这样您就可以快速查找给定集合是否是任何存储集合的超集。
构建数据结构可以花费尽可能长的时间,但是查找应该尽可能高效,并且数据结构不能占用太多空间。
一些上下文
我认为这本身就是一个有趣的问题,但是对于我真正想要解决的问题,您可以假设以下内容:
- N = 10000
- C = 1000
- 存储的数组是稀疏的
- 查找的数组是随机的(所以不是稀疏的)
到目前为止我的想法
对于 O(NC) 查找:只需迭代所有数组。不过这太慢了。
对于 O(C) 查找:我在这里有一个很长的描述,但正如 Amit 在 cmets 中指出的那样,它基本上是一个 BDD。虽然这具有很高的查找速度,但它具有指数级数量的节点。 N 和 C 这么大,太占空间了。
我希望在这个 O(N*C) 和 O(C) 解决方案之间,可能存在一个不需要指数级空间的 O(log(N)*C) 解决方案。
编辑:我提出的一个新想法
-
对于 O(sqrt(N)C) 查找:将数组存储为 prefix trie。查找数组 A 时,如果 A[i]=0,则转到相应的子树,但如果 A[i]=1,则访问 both 个子树。
我的直觉告诉我,如果您假设存储的数组是随机的,这应该使查找的(平均)复杂度为 O(sqrt(N)C)。但是:1.它们不是,数组是稀疏的。 2. 这只是直觉,我无法证明。
我将尝试这个新想法和 BDD 方法,看看这两种方法中哪一种效果最好。
但与此同时,这个问题不是经常发生吗?它没有名字吗?之前没有研究过吗?真的感觉我在这里重新发明轮子。
【问题讨论】:
-
如果数组是静态的,您可以为每个可能的对 (a,b) 预先计算 is_subset(a,b)。需要 10K*10K 位图:= 100M/CHAR_BIT。显然,查找将是 O(1)。
-
@wildplasser:查找的数组不是 N 个存储集之一。 (否则结果将始终为真)。因此,对于查找,我看不到如何使用此位图。此外,所有存储的集合都不会是彼此的子集,因为如果 A 是 B 的子集,我也可以只存储 A。
-
对不起,我读得太快了。使用一些否定逻辑,并将位集扩展到 64 位之外,也许可以调整这个(与 BDD 非常相似):stackoverflow.com/questions/9246017/…
-
你的做法其实和BDD很像。至少知道这样的想法已经存在可以节省您的实施时间。请注意,BDD 通常用于最多数百个变量的通用公式。
-
由于要求的结果应该是一个布尔值,这确实可以作为 BDD 来实现。可变排序可以通过将频率(在 sum(N) 中)最接近 1/2 的位(在 C 中)放在靠近顶部的位置来引导。
标签: algorithm data-structures set complexity-theory time-complexity