8

We have an array and it is unsorted. We know the range is [0,n].

We want to remove duplicates but we cannot use extra arrays and it must run in linear time.

Any ideas? Just to clarify, this is not for homework!

Geoff C.
  • 95
  • 1
  • 1
  • 4
  • I'm not entirely sure you can do this to be honest. I mean there is counting sort, but that requires additional space. – zellio Mar 24 '11 at 04:46
  • I'm with Mimisbrunnr -- I'm not sure this can be done. Googling suggests that using a hashmap (which probably isn't allowed, here) is the fastest, easiest way to do it; If there were a clever, linear-time algorithm that didn't require extra memory it would be easy to find. – Haldean Brown Mar 24 '11 at 04:53
  • Is this an array of ints? Can you reorder the array? – Jeff Mar 24 '11 at 04:53
  • Not language specific. Java would work, I suppose. By additional space regarding counting sort, I assume you mean buckets/arrays, yes? See I thought this couldn't be done either but the person who posed the question insists it can. I get the answer to it on Monday but I am just curious to know what the answer is before then, haha. – Geoff C. Mar 24 '11 at 04:54
  • 1
    Yes, it is an array of ints. You can reorder the array as long as you finish with O(n) running time. – Geoff C. Mar 24 '11 at 04:55
  • @Geoff is the range of integers limited 0..n? Or can it be any int? – Jeff Mar 24 '11 at 04:59
  • 1
    We know that all integers in the array are between 0 and n. – Geoff C. Mar 24 '11 at 05:03
  • @Geoff can you please delete your comments and add them into your question to clarify? – Jeff Mar 24 '11 at 05:34

8 Answers8

13

If the integers are limited 0 to n, you can move through the array, placing numbers by their indices. Every time you replace a number, take the value that used to be there and move it to where it should be. For instance, let's say we have an array of size 8:

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

Where S is our starting point, and we'll use C to keep track of our "current" index below. We start with index 0, and move 3 to the 3 index spot, where 4 is. Save 4 in a temp var.

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

We then put 4 in the index 4, saving what used to be there, 5.

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

Keep going

-----------------
|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 

When we try to replace 7, we see a conflict, so we simply don't place it. We then continue from the starting index S, increment it by 1:

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

1 is fine here, 3 needs to move

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

But 3 is a duplicate, so we throw it away and keep iterating through the rest of the array.

So basically, we move each entry at most 1 time, and iterate through the entire array. That's O(2n) = O(n)

Jeff
  • 1,807
  • 1
  • 15
  • 17
  • 2
    This requires additional space in some cases. What if you have { 0, 1, 20 } as your array? then you need an array of size 20. – zellio Mar 24 '11 at 05:28
  • You probably also need to do compression of the array at the end by removing items that are marked with X above (i.e. -1 could be used to mark missing items). To remove items just go through all elements once and copy to last free space O(n) again. – Alexei Levenkov Mar 24 '11 at 05:31
  • 2
    @Mimisbrunnr Integers are limited from 0..n, where n is the size of the array – Jeff Mar 24 '11 at 05:32
  • 1
    Or did I misread? I agree this won't work if n > the size of the array. – Jeff Mar 24 '11 at 05:38
  • @Mimisbrunnr - If I understand problem correctly, for an array of size 3, you can only have values in range [0,3]. – Joel Lee Mar 24 '11 at 05:41
  • @Jeff +1 - My solution is essentially the same as yours. – Joel Lee Mar 24 '11 at 05:47
  • I think this would do it! Thanks Jeff & all. – Geoff C. Mar 24 '11 at 07:05
3

Assume int a[n] is an array of integers in the range [0,n-1]. Note that this differs slightly from the stated problem, but I make this assumption to make clear how the algorithm works. The algorithm can be patched up to work for integers in the range [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);
     }
 }
Joel Lee
  • 3,656
  • 1
  • 18
  • 21
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]));
  }
}
Pradhan
  • 421
  • 5
  • 17
0

Walk through the array assign array[array[i]] = -array[array[i]]; if not negative; if its already negative then its duplicate, this will work since all values are within 0 and n.

nmd
  • 823
  • 1
  • 7
  • 17
0

Extending @Joel Lee's code for completion.

#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;
}
B Jacob
  • 389
  • 3
  • 9
0

Can you sort? Sort with Radix Sort - http://en.wikipedia.org/wiki/Radix_sort with complexity O(arraySize) for given case and then remove duplicates from sorted array O(arraySize).

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
0

With ES6 I think this can be solved with only a few lines reducing the array into an object and then using object.keys to get array without duplicates. This probably takes more memory. I'm not sure.

I did it like this:

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

This has the added bonus (or disadvantage) of sorting the array. It works with strings too.

0

Use the array a a container with negative sign as an indicator, this will corrupt the input though.

  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 14 '22 at 08:49