算法:从数组中高效地移除重复的整数

93

这个问题来自于微软的面试。

给定一个随机整数数组, 请用 C 语言编写一个算法,去除重复的数字并返回原始数组中的唯一数字。

例如,输入:{4, 8, 4, 1, 1, 2, 9} 输出:{4, 8, 1, 2, 9, ?, ?}

其中一个注意事项是,期望的算法不应该要求先对数组进行排序。当一个元素被移除后,后续的元素必须向前移位。无论如何,被移位的末尾元素的值都是可以忽略的。

更新:结果必须返回到原始数组中,不能使用帮助数据结构(例如哈希表)。然而,我猜想保持元素顺序并不是必需的。

更新2:对于那些想知道为什么有这些不切实际的限制的人,这是一个面试题,所有这些限制都是在思考过程中讨论的,以了解我如何提出不同的想法。


4
你需要保持独特数字的顺序吗? - Douglas Leeder
1
结果必须返回到原始数组中吗? - Douglas Leeder
1
我已经更新了问题。结果应该以原始数组的形式返回。然而,序列的顺序并不重要。 - ejel
3
当有人在问题和其他答案上进行推销时,这是相当让人烦恼的。只要耐心等待,人们最终会有结果的。 - GManNickG
3
为什么不允许使用哈希表?这个限制毫无意义。 - RBarryYoung
显示剩余4条评论
34个回答

1
经过审查问题,这是我的Delphi方法,可能会有所帮助。
var
A: Array of Integer;
I,J,C,K, P: Integer;
begin
C:=10;
SetLength(A,10);
A[0]:=1; A[1]:=4; A[2]:=2; A[3]:=6; A[4]:=3; A[5]:=4;
A[6]:=3; A[7]:=4; A[8]:=2; A[9]:=5;

for I := 0 to C-1 do
begin
  for J := I+1 to C-1 do
    if A[I]=A[J] then
    begin
      for K := C-1 Downto J do
        if A[J]<>A[k] then
        begin
          P:=A[K];
          A[K]:=0;
          A[J]:=P;
          C:=K;
          break;
        end
        else
        begin
          A[K]:=0;
          C:=K;
        end;
    end;
end;

//tructate array
setlength(A,C);
end;

0

这是我得到的,虽然它错位了顺序,但我们可以按升序或降序排序来修复它。

#include <stdio.h>
int main(void){
int x,n,myvar=0;
printf("Enter a number: \t");
scanf("%d",&n);
int arr[n],changedarr[n];

for(x=0;x<n;x++){
    printf("Enter a number for array[%d]: ",x);
    scanf("%d",&arr[x]);
}
printf("\nOriginal Number in an array\n");
for(x=0;x<n;x++){
    printf("%d\t",arr[x]);
}

int i=0,j=0;
// printf("i\tj\tarr\tchanged\n");

for (int i = 0; i < n; i++)
{
    // printf("%d\t%d\t%d\t%d\n",i,j,arr[i],changedarr[i] );
    for (int j = 0; j <n; j++)
    {   
        if (i==j)
        {
            continue;

        }
        else if(arr[i]==arr[j]){
            changedarr[j]=0;

        }
        else{
            changedarr[i]=arr[i];

        }
    // printf("%d\t%d\t%d\t%d\n",i,j,arr[i],changedarr[i] );
    }
    myvar+=1;
}
// printf("\n\nmyvar=%d\n",myvar);
int count=0;
printf("\nThe unique items:\n");
for (int i = 0; i < myvar; i++)
{
        if(changedarr[i]!=0){
            count+=1;
            printf("%d\t",changedarr[i]);   
        }
}
    printf("\n");
}

0
给定一个由n个元素组成的数组,请编写一种算法,以O(nlogn)的时间从数组中删除所有重复项。
Algorithm delete_duplicates (a[1....n])
//Remove duplicates from the given array 
//input parameters :a[1:n], an array of n elements.

{

temp[1:n]; //an array of n elements. 

temp[i]=a[i];for i=1 to n

 temp[i].value=a[i]

temp[i].key=i

 //based on 'value' sort the array temp.

//based on 'value' delete duplicate elements from temp.

//based on 'key' sort the array temp.//construct an array p using temp.

 p[i]=temp[i]value

  return p.

在输出数组中,元素的顺序是根据“键”来维护的。考虑到键的长度为O(n),对键和值进行排序所需的时间为O(nlogn)。因此,从数组中删除所有重复项所需的时间为O(nlogn)。


对于所有粗体字形,你如何理解“不应使用辅助数据结构(例如哈希表)”? - greybeard
不需要。我只是为了理解而突出了那些内容。 - Sharief Muzammil

0

在JAVA中,

    Integer[] arrayInteger = {1,2,3,4,3,2,4,6,7,8,9,9,10};

    String value ="";

    for(Integer i:arrayInteger)
    {
        if(!value.contains(Integer.toString(i))){
            value +=Integer.toString(i)+",";
        }

    }

    String[] arraySplitToString = value.split(",");
    Integer[] arrayIntResult = new Integer[arraySplitToString.length];
    for(int i = 0 ; i < arraySplitToString.length ; i++){
        arrayIntResult[i] = Integer.parseInt(arraySplitToString[i]);
    }

输出结果: {1、2、3、4、6、7、8、9、10}

希望这可以帮到你


1
用输入arrayInteger = {100, 10, 1};测试。 - Blastfurnace

0

0

可以在单次遍历中完成,时间复杂度为输入列表中整数的数量O(N),存储空间复杂度为唯一整数的数量O(N)。

从前往后遍历列表,使用两个指针“dst”和“src”初始化为第一个项目。从一个空的“已见整数”哈希表开始。如果src处的整数不存在于哈希表中,则将其写入dst处的插槽并增加dst。将src处的整数添加到哈希表中,然后增加src。重复此过程,直到src超过输入列表的末尾。


2
在对原问题进行修改时,不允许使用哈希表。然而,你的双指针方法是一种很好的方式,在确定重复项后压缩输出。 - Mark Ransom

0

将所有元素插入一个忽略重复项的二叉树 - O(nlog(n))。然后通过遍历将它们全部提取回数组 - O(n)。我假设您不需要保留顺序。


0
使用布隆过滤器进行散列。这将显著降低存储器开销。

能否详细说明或提供参考资料? - dldnh

0
首先,你应该创建一个数组check[n],其中n是你想要使其不重复的数组元素数量,并将每个元素(检查数组的元素)的值设置为1。使用for循环遍历带有重复项的数组,假设其名称为arr,在for循环中写入以下内容:
{
    if (check[arr[i]] != 1) {
        arr[i] = 0;
    }
    else {
        check[arr[i]] = 0;
    }
}

有了这个,你把每个重复的元素都设为零。所以唯一剩下的事情就是遍历arr数组并打印出所有不等于零的元素。顺序保持不变,时间复杂度为线性时间(3*n)。


该问题不允许使用额外的数据结构。 - ejel

-1

如果你有一个好的数据结构,可以快速地判断它是否包含整数,那就太棒了。也许是某种树结构。

DataStructure elementsSeen = new DataStructure();
int elementsRemoved = 0;
for(int i=0;i<array.Length;i++){
  if(elementsSeen.Contains(array[i])
    elementsRemoved++;
  else
    array[i-elementsRemoved] = array[i];
}
array.Length = array.Length - elementsRemoved;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接