2

I have to solve an exercise with the following criteria:

Compare two arrays:

int[] a1 = {1, 3, 7, 8, 2, 7, 9, 11};
int[] a2 = {3, 8, 7, 5, 13, 5, 12};

Create a new array int[] with only unique values from the first array. Result should look like this: int[] result = {1,2,9,11};

NOTE: I am not allowed to use ArrayList or Arrays class to solve this task.

I'm working with the following code, but the logic for the population loop is incorrect because it throws an out of bounds exception.

public static int[] removeDups(int[] a1, int[] a2) {
    //count the number of duplicate values found in the first array
    int dups = 0;
    for (int i = 0; i < a1.length; i++) {

        for (int j = 0; j < a2.length; j++) {
            if (a1[i] == a2[j]) {
                dups++;
            }
        }
    }
    //to find the size of the new array subtract the counter from the length of the first array
    int size = a1.length - dups;
    //create the size of the new array
    int[] result = new int[size];

    //populate the new array with the unique values
    for (int i = 0; i < a1.length; i++) {
        int count = 0;
        for (int j = 0; j < a2.length; j++) {
            if (a1[i] != a2[j]) {
                count++;
                if (count < 2) {
                    result[i] = a1[i];
                }
            }
        }
    }

    return result;
}

I would also love how to solve this with potentially one loop (learning purposes).

5
  • Is it allowed for you to use 'Map'? Commented Sep 22, 2018 at 20:49
  • Are you allow to use any tree structure (e.g. binary search tree, etc.)? Or do you have to do this strictly with loops? Commented Sep 22, 2018 at 20:49
  • I don't believe so. It's not an advanced exercise. Commented Sep 22, 2018 at 20:53
  • 1
    Search for "array difference". For unsorted input, this requires at least two loops (counting implicit loops, and not necessarily used as currently show-) Commented Sep 22, 2018 at 21:20
  • 1
    If all the numbers are integers in a small range, the basis of a "counting sort" might be useful to explore.. Commented Sep 22, 2018 at 21:26

4 Answers 4

2

I offer following soulution.

  1. Iterate over first array, and find out min and max it's value.
  2. Create temporary array with length max-min+1 (you could use max + 1 as a length, but it could follow overhead when you have values e.g. starting from 100k).
  3. Iterate over first array and mark existed values in temorary array.
  4. Iterate over second array and unmark existed values in temporary array.
  5. Place all marked values from temporary array into result array.

Code:

public static int[] getUnique(int[] one, int[] two) {
    int min = Integer.MAX_VALUE;
    int max = Integer.MIN_VALUE;

    for (int i = 0; i < one.length; i++) {
        min = one[i] < min ? one[i] : min;
        max = one[i] > max ? one[i] : max;
    }

    int totalUnique = 0;
    boolean[] tmp = new boolean[max - min + 1];

    for (int i = 0; i < one.length; i++) {
        int offs = one[i] - min;
        totalUnique += tmp[offs] ? 0 : 1;
        tmp[offs] = true;
    }

    for (int i = 0; i < two.length; i++) {
        int offs = two[i] - min;

        if (offs < 0 || offs >= tmp.length)
            continue;
        if (tmp[offs])
            totalUnique--;
        tmp[offs] = false;
    }

    int[] res = new int[totalUnique];

    for (int i = 0, j = 0; i < tmp.length; i++)
        if (tmp[i])
            res[j++] = i + min;

    return res;
}
Sign up to request clarification or add additional context in comments.

1 Comment

The time complexity is not related to n (input size) when k >> n.. (k is the size of the temp array, which depends on the values and not the count of values) :}
1

For learning purposes, we won't be adding new tools.

Let's follow the same train of thought you had before and just correct the second part:

// populate the new array with the unique values
for (int i = 0; i < a1.length; i++) {
    int count = 0;
    for (int j = 0; j < a2.length; j++) {
        if (a1[i] != a2[j]) {
            count++;
            if (count < 2) {
                result[i] = a1[i];
            }
        }
    }
}

To this:

//populate the new array with the unique values
int position = 0;
for (int i = 0; i < a1.length; i++) {
    boolean unique = true;

    for (int j = 0; j < a2.length; j++) {
        if (a1[i] == a2[j]) {
            unique = false;
            break;
        }
    }

    if (unique == true) {
        result[position] = a1[i];
        position++;
    }
}

I am assuming the "count" that you implemented was in attempt to prevent false-positive added to your result array (which would go over). When a human determines whether or not an array contains dups, he doesn't do "count", he simply compares the first number with the second array by going down the list and then if he sees a dup (a1[i] == a2[j]), he would say "oh it's not unique" (unique = false) and then stop going through the loop (break). Then he will add the number to the second array (result[i] = a1[i]).

So to combine the two loops as much as possible:

// Create a temp Array to keep the data for the loop
int[] temp = new int[a1.length];

int position = 0;
for (int i = 0; i < a1.length; i++) {
    boolean unique = true;

    for (int j = 0; j < a2.length; j++) {
        if (a1[i] == a2[j]) {
            unique = false;
            break;
        }
    }

    if (unique == true) {
        temp[position] = a1[i];
        position++;
    }
}

// This part merely copies the temp array of the previous size into the proper sized smaller array
int[] result = new int[position];

for (int k = 0; k < result.length; k++) {
    result[k] = temp[k];
}

Comments

0

Making your code work

Your code works fine if you correct the second loop. Look at the modifications I did:

//populate the new array with the unique values
int counter = 0;
for (int i = 0; i < a1.length; i++) {
    for (int j = 0; j < a2.length; j++) {
        if (a1[i] == a2[j]) {
              result[counter] = a1[i];
              counter++;
        }
    }
}




The way I would do it

Now, here is how I would create a method like this without the need to check for the duplicates more than once. Look below:

public static int[] removeDups(int[] a1, int[] a2) {
    int[] result = null;
    int size = 0;

    OUTERMOST: for(int e1: a1) {
      for(int e2: a2) {
        if(e1 == e2)
          continue OUTERMOST;
      }

      int[] temp = new int[++size];
      if(result != null) {
        for(int i = 0; i < result.length; i++) {
          temp[i] = result[i];
        }
      }

      temp[temp.length - 1] = e1;
      result = temp;
    }

    return result;
}

Instead of creating the result array with a fixed size, it creates a new array with the appropriate size everytime a new duplicate is found. Note that it returns null if a1 is equal a2.

Comments

-2

You can make another method to see if an element is contained in a list :

public static boolean contains(int element, int array[]) {
    for (int iterator : array) {
        if (element == iterator) {
            return true;
        }
    }
    return false;
}

Your main method will iterate each element and check if it is contained in the second:

int[] uniqueElements = new int[a1.length];
int index = 0;
for (int it : a1) {
   if (!contains(it, a2)) {
       uniqueElements[index] = it;
       index++;
    }
}

2 Comments

Interesting approach, but doing it this way will result in the returned array (uniqueElements) always having the same size of a1.
Yes, I wanted to avoid another loop to find the array size and the worst case is that every element is not contained in the second array.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.