有没有办法在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}
将给我们{{1但是这需要{29,81,43}
时间。
是否有O(N)算法来解决这个问题?
P.S。我忘了添加:我不想使用哈希表。我正在寻找一个非哈希解决方案。
答案 0 :(得分:16)
我相信一个好的解决方案(可靠的内存使用,可以用来立即确定是否已经看到一个条目因此保留了顺序,并具有线性复杂性)是a trie。
如果将元素插入到trie中,就好像它们是每个节点中每个数字(从MSD开始)的字符串一样,您可以将其复杂化为O( m N )其中 m 是基数为10位的平均数字长度。
您只需遍历所有条目并将其插入到trie中即可。每次元素已经存在时,您跳过它并继续下一个元素。这里的重复(与我之前的基数排序答案不同)将立即找到,而不是在最后一次迭代中找到 。
我不确定你是否会从这里使用后缀树中受益,因为输入到trie中的字符的“基数”只有10(与ANSI字符串的128基数相比),但它可能
答案 1 :(得分:8)
如果你的输入都是小整数,你可以使用counting sort,它在O(n)时间内运行,需要O(m)空间,其中m是可能输入范围的大小。
作为空间优化,使用位数组并使用单个位(而不是计数)来存储您之前是否看过该项是足够的。
答案 2 :(得分:3)
听起来你不喜欢分配任何额外的空间。尽管如此,哈希表仍然是速度的正确解决方案。老实说,大多数简单数据(如整数)的哈希表实现都超出了他们的一个解决方案适合所有性质,我根据自己的需要自行推出。当您需要相对较少的工作时,它可以将慢速代码转换为快速代码。
此外,如果您对哈希表的反对意见是他们破坏了顺序,那么您可能希望在保持顺序的同时使用它们以获得预期的O(n):
创建一个哈希表,将数组元素映射为两位作为从0到3的计数字段,并将30位作为元素数组的索引。除非你的数组中有超过十亿的值,否则三十位就足够了。这样,您的哈希值只是一个32位字。
浏览数组中的元素。如果元素不在表中,请将值插入哈希表并将count字段设置为零。存储它时索引部分是什么并不重要。如果元素在表中并且count字段为零,则将其提升为1并使用新的count字段值存储元素索引。如果count字段已经是1或更大,请将其设置为2并且不要触摸存储的索引 - 保持原样。
再次遍历数组中的元素。查找每个元素,如果其索引是存储的并且关联的计数字段大于零,则将其打印出来。
这应该以O(n)时间以正确的顺序产生你想要的东西。但是,它使用的散列表是出于未知原因所不需要的。我强烈建议您接受这样的解决方案或解释限制,以便您获得更准确的目标解决方案。
答案 3 :(得分:1)
如果您知道最大值,可以这样做,
有一个单独的数组,其长度为最大值
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]);
}
}
答案 4 :(得分:0)
您可以在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的绝对值。 然后,值为&gt; 1的(arraynew +)和((arraynew-)的所有索引都是arrayorig的不同值。
答案 5 :(得分:0)
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]));
}
}
答案 6 :(得分:-3)
查找重复项与排序一样困难。您最好的选择是利用输入的某些属性来获得O(N)排序。