繁体   English   中英

在O(N)时间内在数组中查找重复项

[英]Find Duplicates in an array in O(N) time

有没有办法在O(N)时间内找到N个元素数组中的所有重复元素?

例:

输入: 11, 29, 81, 14, 43, 43, 81, 29

产出: 29, 81, 43

对输入进行排序并进行线性扫描以检测重复项会破坏顺序并提供输出:29,43,81。

根据给定的数组按键排序另一个索引{0,1,...N-1}数组,得到{1,4,2} ,然后将得到的索引集排序为{1,2,4}将给我们{29,81,43} ,但这需要O(N logN)时间。

是否有O(N)算法来解决这个问题?

PS我忘记添加:我不想使用哈希表。 我正在寻找一个非哈希解决方案。

我相信一个很好的解决方案(可靠的内存使用,可以用来立即确定是否已经看到一个条目因此保留顺序,并具有线性复杂性)是一个特里

如果将元素插入到trie中,就好像它们是每个节点中每个数字(从MSD开始)的字符串一样,您可以将其复杂化为O( m N),其中m是数字的平均长度。基数为10位数。

您只需遍历所有条目并将其插入到trie中。 每次元素已经存在时,您跳过它并继续下一个元素。 这里的重复(不像我以前的Radix排序的答案) 立即找到,而不是在最后一次迭代中或不是。

我不确定你是否会从这里使用后缀树中受益,因为输入到trie中的字符的“基础”只有10(与ANSI字符串的基数128相比),但这是可能的。

如果输入都是小整数,则可以使用在O(n)时间内运行的计数排序 ,并且需要O(m)空间,其中m是可能输入范围的大小。

作为空间优化,使用位数组并使用单个位(而不是计数)来存储您之前是否看过该项是足够的。

听起来你不喜欢分配任何额外的空间。 尽管如此,哈希表仍然是速度的正确解决方案。 老实说,大多数简单数据(如整数)的哈希表实现都超出了他们的一个解决方案适合所有性质,我根据自己的需要自行推出。 当您需要相对较少的工作时,它可以将慢速代码转换为快速代码。

此外,如果您对哈希表的反对意见是它们会破坏顺序,那么您可能希望在保持顺序的同时使用它们以获得预期的O(n):

创建一个哈希表,将数组元素映射为两位作为从0到3的计数字段,并将30位作为元素数组的索引。 除非你的数组中有超过十亿的值,否则三十位就足够了。 这样,您的哈希值只是一个32位字。

浏览数组中的元素。 如果元素不在表中,请将值插入哈希表并将count字段设置为零。 存储它时索引部分是什么并不重要。 如果元素在表中并且count字段为零,则将其提升为1并使用新的count字段值存储元素索引。 如果计数字段已经是1或更大,请将其设置为2并且不要触摸存储的索引 - 保持原样。

再次遍历数组中的元素。 查找每个元素,如果其索引是存储的并且关联的计数字段大于零,则将其打印出来。

这应该以O(n)时间以正确的顺序产生你想要的东西。 但是,它使用的散列表是出于未知原因所不需要的。 我强烈建议您接受此类解决方案或解释限制,以便获得更准确的目标解决方案。

如果你知道你可以这样做的最大值,
有一个单独的数组,其长度为最大值

 int[max] secondarray;

    for(int i=o;i<arrayFirst.length;i++){
        if(secondarray[arrayFirst[i]]==0){
            secondarray[arrayFirst[i]]==arrayFirst[i];
         }else{
             result.add(arrayFirst[i]);
          }
     }

你可以在O(n)中执行此操作,但这需要数组为整数。 这需要的空间可以是订单大小-2 ^ 32到2 ^ 32。 你需要做的是找到原始数组的最大值和最小值(arrayorig)。 然后制作两个数组(arraynew +)和(arraynew-)。

如果arrayorig中的所有值都是+,则(arraynew +)的大小将是max(arraorig)-min(arrayorig),否则(arraynew +)的大小将是max(arrayorig)。

如果所有值都是正数,则size(arraynew-)将为零,否则它们将等于min(arrayorig)的绝对值。

然后你可以遍历arrayorig并在对应于arraorig值的索引处将值(arraynew-)或(arraynew +)的值递增1,如果值为正数,则应该对(arraynew +)执行,否则为负值增量应该在(arraynew-)索引处(arraynew-)完成,它等于arrayorig的绝对值。 然后,值> 1的(arraynew +)和((arraynew-)的所有索引都是arrayorig的不同值。

 void printRepeating(int arr[], int size)
 {
 int i;
   printf("The repeating elements are: \n");
 for (i = 0; i < size; i++)
 {
 if (arr[abs(arr[i])] >= 0)
  arr[abs(arr[i])] = -arr[abs(arr[i])];
 else
  printf(" %d ", abs(arr[i]));
 }
  }

查找重复项与排序一样困难。 您最好的选择是利用输入的某些属性来获得O(N)排序。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM