在线性时间内从阵列中删除重复项,无需额外的数组

时间:2011-03-24 04:41:13

标签: arrays

我们有一个数组,它是未分类的。我们知道范围是[0,n]。

我们希望删除重复项,但我们不能使用额外数组,并且必须以线性时间运行

有什么想法吗?只是为了澄清,这不是作业!

7 个答案:

答案 0 :(得分:8)

如果整数限制为0到n,则可以在数组中移动,按索引放置数字。每次更换一个数字时,取出以前的值并将其移动到应该的位置。例如,假设我们有一个大小为8的数组:

-----------------
|3|6|3|4|5|1|7|7|
-----------------
 S

其中S是我们的起点,我们将使用C来跟踪下面的“当前”指数。 我们从索引0开始,并将3移动到3索引点,其中4是。在临时变量中保存4。

-----------------
|X|6|3|3|5|1|7|7|   Saved 4 
-----------------  
 S     C

然后我们在索引4中加上4,保存了那里的原因,5。

-----------------
|X|6|3|3|4|1|7|7|   Saved 5
-----------------
 S       C

继续前进

-----------------
|X|6|3|3|4|5|7|7|   Saved 1
-----------------
 S         C

-----------------
|X|1|3|3|4|5|7|7|   Saved 6
-----------------
 S C

-----------------
|X|1|3|3|4|5|6|7|   Saved 7    
-----------------
 S           C 

当我们尝试替换7时,我们会发现冲突,所以我们根本就不会放置它。然后我们从起始索引S继续,将其递增1:

-----------------
|X|1|3|3|4|5|6|7| 
-----------------  
   S           

1这里很好,3需要移动

-----------------
|X|1|X|3|4|5|6|7|
-----------------
     S

但是3是重复的,所以我们把它扔掉并继续遍历数组的其余部分。

基本上,我们最多移动每个条目一次,并遍历整个数组。那是O(2n)= O(n)

答案 1 :(得分:3)

假设int a[n]是[0,n-1]范围内的整数数组。请注意,这与所述问题略有不同,但我做出此假设以明确算法的工作原理。该算法可以修补以适用于[0,n]范围内的整数。

for (int i=0; i<n; i++)
{
    if (a[i] != i)
    {
         j = a[i];
         k = a[j];
         a[j] = j;  // Swap a[j] and a[i]
         a[i] = k;
     }
 }

 for (int i=0; i<n; i++)
 {
     if (a[i] == i)
     {
        printf("%d\n", i);
     }
 }

答案 2 :(得分:3)

    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]));
  }
}

答案 3 :(得分:0)

你可以排序吗?使用基数排序 - http://en.wikipedia.org/wiki/Radix_sort排序,复杂度为O(arraySize),然后从排序数组O(arraySize)中删除重复项。

答案 4 :(得分:0)

遍历数组assign array [array [i]] = -array [array [i]];如果不是消极的;如果它已经是负数然后它的副本,这将起作用,因为所有值都在0和n之内。

答案 5 :(得分:0)

扩展@Joel Lee的代码以完成。

#include <iostream>
void remove_duplicates(int *a, int size)
{
  int i, j, k;
  bool swap = true;

   while(swap){
    swap = false;
    for (i=0; i<size; i++){
        if(a[i] != i && a[i] != a[a[i]]){
            j = a[i];
            k = a[j];
            a[i] = k;
            a[j] = j;
            swap = true;      
        }

    }
    }
}

int main()
{
    int i;
    //int array[8] = {3,6,3,4,5,1,7,7};
    int array[8] = {7,4,6,3,5,4,6,2};

    remove_duplicates(array, sizeof(array)/sizeof(int));

    for (int i=0; i<8; i++)
        if(array[i] == i)
            std::cout << array[i] << " ";

    return 0;
}

答案 6 :(得分:0)

我认为使用ES6只需几行就可以解决,将数组简化为一个对象,然后使用object.keys获得没有重复的数组。这可能需要更多的内存。我不确定。

我是这样做的:

var obj = array.reduce(function (acc, elem) {
      acc[elem] = true;
      return acc;
    },{});
var uniqueArray = Object.keys(obj);

这具有对数组进行排序的额外好处(或缺点)。它也适用于字符串。