我有一个应用,其中有O(n)
个列表。
每个集合Set(i)
是一个n-vector
。例如,假设n=4
Set(1)
可能是[0|1|1|0]
Set(2)
可能是[1|1|1|0]
Set(3)
可能是[1|1|0|0]
Set(4)
可能是[1|1|1|0]
我想处理这些集合,以便仅将其中的唯一集合作为输出。因此,在上面的示例中,我将得到以下输出:
Set(1), Set(2), Set(3)
。请注意,Set(4)
与Set(2)
相同,因此已被丢弃。
一种相当蛮力的方法可以解决这个问题,这给了我O(n^3)
的最坏情况:
Given: Input List of size O(n)
Output List L = Set(1)
for(j = 2 to Length of Input List){ // Loop Outer, check if Set(j) should be added to L
for(i = 1 to Length of L currently){ // Loop Inner
check if Set(i) is same as Set(j) //This step is O(n) since Set() has O(n) elements
if(they are same) exit inner loop
else
if( i is length of L currently) //so, Set(j) is unique thus far
Append Set(j) to L
}
}
n
上没有先验约束:它可以任意大。这似乎排除了使用简单的哈希函数(将二进制集映射到十进制)的可能性。我可能是错的。
除了O(n^3)
以外,还有其他方法可以在最坏的情况下更好地运行吗?
答案 0 :(得分:3)
O(n)个序列的大小为O(n ^ 2)。您不会比这更好的复杂性,因为可能至少需要您阅读所有输入。例如,所有序列都可能是相同的,但是您必须全部阅读它们才能知道这一点。
可以将长度为n的二进制序列插入到trie或基数树中,同时在O(n)时间内检查是否已经存在。对于所有序列来说,它们的总和都是O(n ^ 2),因此简单地使用trie或基数树查找重复项是最佳选择。
请参阅:https://en.wikipedia.org/wiki/Trie 和:https://en.wikipedia.org/wiki/Radix_tree
答案 1 :(得分:2)
您可以考虑使用平衡的二叉树实现集合。在这样的树中插入新节点的成本为O(lgm)
,其中m
是树中元素的数量。重复将被隐式删除,因为如果我们检测到这样的节点已经存在,那么就不会添加它。
在您的示例中,查找/插入操作的总数为n*n
,因为有n
个集合,每个集合都有n
个值。因此,总时间可能会缩放为O(n^2*lg(n^2))
。胜过O(n^3)
。
答案 2 :(得分:1)
首先,这些不是集合而是位串。
接下来,对于每个位串,您都可以将其转换为数字并将该数字放入哈希集中(或简单地存储原始位串,大多数哈希集实现都可以做到这一点)。之后,您的哈希集将包含所有唯一项。 O(N)时间,O(N)空间。如果需要保持字符串的原始顺序,则在第一个循环中检查每个字符串是否已经在哈希集中,如果不是,则将其输出并插入哈希集中。
答案 3 :(得分:0)
如果您可以使用O(n)多余的空间,则可以尝试以下操作:
首先,让我们假设向量是二进制数,因此0110变为6。
将所有矢量转换为小数将花费O(4n)。 对于每个转换后的数字,我们将通过十进制数字映射向量。为了实现这一点,我们将使用一个n大小的哈希图。
按步骤运行: