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

C++ 在O(N)时间内查找数组中的重复项,c++,algorithm,C++,Algorithm,有没有办法在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)算法来解决这个问题 另外,我忘了补充:我不想使用哈希表。我正在寻找一个非散列解

有没有办法在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)算法来解决这个问题


另外,我忘了补充:我不想使用哈希表。我正在寻找一个非散列解决方案。

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


作为一种空间优化,使用一个位数组并使用一个位(而不是一个计数)来存储您以前是否见过该项就足够了。

如果您知道可以这样做的最大值,
使用长度作为最大值的单独数组

 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]);
          }
     }
int[max]secondarray;

对于(int i=o;i查找重复项与排序一样困难。您最好利用输入的某些属性来获得o(N)排序。

听起来您不赞成分配任何额外的空间。尽管如此,哈希表仍然是提高速度的正确解决方案。老实说,大多数简单数据(如整数)的哈希表实现都是如此超重,因为它们的一个解决方案适合所有人,所以我只能根据需要滚动自己的哈希表。这可能会降低代码的速度当您需要快速代码完成相对较少的工作时,将其转换为快速代码

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

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

检查数组中的元素。如果某个元素不在表中,请将该值插入哈希表并将count字段设置为零。存储它时,索引部分是什么并不重要。如果元素在表中且count字段为零,请将其增加到1,并使用新的count字段值存储元素索引。如果e count字段已经是一个或更多,请将其设置为两个,不要触摸存储的索引——保持原样

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

这将以O(n)时间的正确顺序为您提供所需的内容。但是,它使用的哈希表出于未知原因而不需要。我强烈建议您接受这样的解决方案,或者解释其局限性,以便获得更准确的目标解决方案。

我相信这是一个好的解决方案(适当的内存使用,可用于立即确定是否已看到条目,从而保持顺序,并具有线性复杂性)是

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

您只需循环所有条目并将它们插入trie中。每次元素已经存在时,您都会跳过它并转到下一个元素。此元素中的重复项(与我之前的基数排序答案不同)将立即被找到,而不是在上一次迭代或其他迭代中

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

您可以在O(n)中执行此操作,但这将要求数组为整数。此操作所需的空间大小可以是-2^32到2^32。 您需要做的是找到原始数组(ArrayRog)的最大值和最小值,然后创建两个数组(arraynew+)和(arraynew-)

如果ArrayRog中的所有值均为+,则(arraynew+)的大小将为max(ArrayRoig)-min(ArrayRoig),否则(arraynew+)的大小将为max(ArrayRoig)

如果所有值均为正值,则大小(arraynew-)将为零,否则它们将等于最小值的绝对值(ArrayRoig)

然后,您可以迭代ArrayRog,并在与ArrayRoig值相对应的索引处将该值增加(arraynew-)或(arraynew+),如果该值为正,则应增加(arraynew+),如果该值为负,则应增加(arraynew-)索引处的(arraynew-)等于ArrayRog的绝对值。 那么值大于1的(arraynew+)和((arraynew-)的所有索引都是ArrayRog的不同值。

void printRepeating(int arr[],int size)
 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]));
 }
  }
{ int i; printf(“重复元素为:\n”); 对于(i=0;i=0) arr[abs(arr[i])]=-arr[abs(arr[i]); 其他的 printf(“%d”,abs(arr[i]); } }
如果空间不是限制,则将每个元素存储在散列中。当发生冲突时,您有一个重复的元素。@Anurag:最佳情况/平均运行时间为O(n),但最坏情况为O(n2)@Anurag:你说的散列到底是什么意思?@Charles Bailey:我想他指的是映射。你为什么要寻找非散列解决方案?这样做会让你知道哪些元素是重复的。要按原始顺序获取元素,请将哪些元素是重复的存储在位向量中,然后对原始数据进行另一次线性扫描,输出重复的元素,s直至O(n),,