示例:
输入: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)算法来解决这个问题?
附言:我忘了添加:我不想使用哈希表。 我正在寻找一个非哈希解决方案。
我认为一个很好的解决方案(内存使用较少,可以立即确定一个条目是否已经被查看,从而保留顺序,并具有线性复杂度)就是trie树。
如果您将每个数字(从最高位开始)作为节点插入到trie树中,您可以以O(mN)的复杂度完成此操作,其中m是10进制数字中数值的平均长度。
您只需要循环遍历所有条目并将它们插入trie树。每次发现元素已经存在时,跳过该元素并继续下一个。与我的上一个答案中的基数排序不同,这种方法中的重复项会立即被发现,而不是在最后一次迭代之前。
我不确定在这里使用后缀树是否有益处,因为输入到trie树中的字符的“基数”仅为10(与ANSI字符串的基数-128相比)。但这是可能的。
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]);
}
}
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)的时间复杂度内完成这个操作,但需要将数组转换为整数类型。所需的空间大小大致为-2^32到2^32的数量级。
你需要做的是找到原始数组(arrayorig)的最大值和最小值,然后创建两个新数组(arraynew+)和(arraynew-)。
如果arrayorig中的所有值都是正数,则(arraynew+)的大小将为max(arrayorig)-min(arrayorig),否则(arraynew+)的大小将为max(arrayorig)。
如果所有值都是正数,则(arraynew-)的大小为零,否则它们将等于min(arrayorig)的绝对值。
然后,您可以遍历arrayorig并将值加1到(arraynew-)或(arraynew+)的索引处,如果值为正,则应将其增加到(arraynew+),否则如果值为负,则应将其增加到(arraynew-)的索引处,该索引等于arrayorig的绝对值。
然后,(arraynew+)和(arraynew-)中所有值>1的索引就是arrayorig的不同值。
查找重复项和排序同样困难。最好的方法是利用输入的某些属性,以便获得 O(N) 的排序。