如何在不排序的情况下从数组中删除重复项

时间:2010-07-08 18:41:55

标签: lua duplicate-removal

我有一个可能包含重复对象的数组。 我想知道是否有可能找到并删除数组中的重复项: - 无需排序(严格要求) - 不使用临时二级数组 - 可能在O(N)中,N是数组中元素的nb

在我的例子中,数组是一个Lua数组,其中包含表:

t={
{a,1},
 {a,2},
 {b,1},
 {b,3},
 {a,2}
} 

就我而言,t [5]是t [2]的副本,而t [1]则不是。[/ p>

4 个答案:

答案 0 :(得分:3)

总而言之,您有以下选择:

  • 时间:O(n ^ 2),没有额外的内存 - 对于数组中的每个元素,线性地查找相等的内容
  • 时间:O(n * log n),没有额外的内存 - 排序第一,在
  • 后线性遍历数组
  • time:O(n),memory:O(n) - 使用查找表(编辑:这可能不是一个选项,因为就我记忆而言,表不能是其他表中的键)

选一个。在没有额外记忆的情况下,没有办法在O(n)时间内做你想做的事。

答案 1 :(得分:2)

不能在O(n)中完成但是......

你可以做的是

  • 通过数组迭代
  • 对于每个成员搜索重复,请删除它们。

最差情况复杂度为O(n ^ 2)

答案 2 :(得分:0)

迭代数组,将每个值都放在哈希中,检查它是否存在。如果确实从原始数组中删除(或者不写入新数组)。内存效率不是很高,但只有0(n),因为你只迭代一次数组。

答案 3 :(得分:0)

是的,取决于你如何看待它。

您可以覆盖对象插入以防止插入重复的项目。这是每个对象插入的O(n),对于较小的数组可能感觉更快。

如果提供排序对象插入和删除,则为O(log n)。基本上,您总是在插入和删除时对列表进行排序,以便查找元素是二进制搜索。这里的成本是元素检索现在是O(log n)而不是O(1)。

这也可以使用红黑树和多树的方式有效地实现,但代价是额外的内存。这些实现为某些问题提供了若干益处。例如,通过使用嵌套树,我们可以使用O(log n)类型的行为,即使是非常大的表,内存占用量也很小。顶级树提供数据集的一种配对向下概述,而子树在需要时提供更精确的访问。

例如,要看到这个假设我们有N个元素。我们可以把它分成n1组。然后,这些组中的每一个可以进一步分成n2个组,并将这些组分成n2个组。因此我们的深度为N / n1n2 ......

正如你所看到的,即使对于小n,n的产品也会变得非常快。如果N = 1万亿个元素并且n1 = 1000,则n2 = 1000,n3 = 1000,每个访问时间仅需1000 + 1000 + 1000 + 1000s = 4000。此外,我们每个节点的内存占用量只有10 ^ 9次。

将此与直接线性搜索所需的平均500亿访问时间进行比较。它比二叉树快1亿倍,内存少1000倍,但速度慢大约100倍! (当然,保持树的一致性有一些开销,但即使这样也可以减少)。

如果我们使用二叉树,那么其深度约为40.问题是大约有1万亿个节点,因此需要大量的额外内存。通过为每个节点存储多个值(在上面的例子中,每个节点实际上是部分值和其他树),我们可以显着减少内存占用,但仍然具有令人印象深刻的性能。

基本上线性访问以较低的数字占优势,树以较高的数量占优势。树的。树消耗更多内存。通过使用多树,我们可以通过对较小数字使用线性访问并且每个节点具有更多元素(与二叉树相比)来组合两者中的最佳组合。

这样的树创建并不简单,但基本上遵循标准二叉树,红黑树,AVL树等的相同算法性质......

因此,如果您正在处理大型数据集,那么性能和内存并不是一个大问题。基本上,正如你可能知道的那样,随着一个人上升,另一个上升。 Multitree,有点找到最佳媒介。 (假设您正确选择了节点大小)


多树的深度是N /乘积(n_k,k = 1..m)。内存占用量是产品的节点数(n_k,k = 1..m)(通常可以减少一个数量级或可能是n_m)