Thursday, November 19, 2009

Distinct intersecting values of two arrays

I have written two different methods that gives the same output. The output is a list of distinct intersecting values of two arrays. I am amazed with the different amount of time taken to solve this problem. It would be something interesting to investigate. Here are the suggested solutions:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

public class ArraysIntersection {

private void findIntersectionMethod1(int[] a, int[] b){
long start = System.nanoTime();
int indexA = 0;
int indexB = 0;
ArrayList unique = new ArrayList();
while (indexA < a.length && indexB < b.length) {
if (a[indexA] == b[indexB]) {
if (!unique.contains(a[indexA])) {
unique.add(a[indexA]);
}
indexA++;
indexB++;
} else if (a[indexA] < b[indexB]) {
indexA++;
} else {
indexB++;
}
}
long elapsed = (System.nanoTime() - start);
System.out.println("Elapsed time (findIntersectionMethod1): " + elapsed + "ns");
System.out.println("Intersection of elements: " + unique);
}

private void findIntersectionMethod2(int[] arr1, int[] arr2){
long start = System.nanoTime();
ArrayList unique = new ArrayList();
for (int i = 0; i < arr1.length; i++) {
for (int j = 0; j < arr2.length; j++) {
if (arr1[i] == arr2[j]) {
if (!unique.contains(arr1[i])) {
unique.add(arr1[i]);
}
}
}
}
long elapsed = (System.nanoTime() - start);
System.out.println("Elapsed time (findIntersectionMethod2): " + elapsed + "ns");
System.out.println("Intersection of elements: " + unique);
}

private void findIntersectionMethod3(int[] a, int[] b){
long start = System.nanoTime();
Set unique = new HashSet();
int indexA = 0;
int indexB = 0;
while (indexA < a.length && indexB < b.length) {
if (a[indexA] == b[indexB]) {
unique.add(a[indexA]);
indexA++;
indexB++;
} else if (a[indexA] < b[indexB]) {
indexA++;
} else {
indexB++;
}
}

long elapsed = (System.nanoTime() - start);
System.out.println("Elapsed time (findIntersectionMethod3): " + elapsed + "ns");
System.out.println("Intersection of elements: " + unique);
}

public static void main(String[] args) {

int a[]={1, 1, 2, 4, 4, 7, 8, 8, 9, 14, 14, 20, 20, 20};
int b[]={1, 1, 1, 2, 2, 8, 8, 20};

ArraysIntersection arrIntersect = new ArraysIntersection();
arrIntersect.findIntersectionMethod1(a, b);
arrIntersect.findIntersectionMethod2(a, b);
arrIntersect.findIntersectionMethod3(a, b);
}
}

The output of these methods are as below (I'm telling you, you'll be amazed looking at the time taken for each method):
Elapsed time (findIntersectionMethod1): 455000ns
Intersection of elements: [1, 2, 8, 20]
Elapsed time (findIntersectionMethod2): 15000ns
Intersection of elements: [1, 2, 8, 20]
Elapsed time (findIntersectionMethod3): 65000ns
Intersection of elements: [2, 8, 1, 20]

I'm sure there are much better solutions to solve this interesting problem that I have not thought of.

9 comments:

  1. wow, I'd think the first one would perform better (theoretically)..

    ReplyDelete
  2. Are you sure you need this:
    # if (a[indexA] == t)
    # indexA++;
    # if (b[indexB] == t)
    # indexB++;

    when a[indexA] already equals to b[indexB] in the preceeding if statement and t is assigned the value of a[IndexA]?

    seems to me those indexes can be incremented unconditionally. What do you think?

    ReplyDelete
  3. hmmm ... let me investigate if i ever need those conditions

    ReplyDelete
  4. leo, you are right.
    i have changed my code to use these to increments

    indexA++;
    indexB++;

    and I'm able to save a few fraction of time because we are not doing any conditional checkings

    ReplyDelete
  5. i have also removed
    int t = a[indexA];

    in the previous code and saved another fraction of time

    ReplyDelete
  6. I somehow don't think these results are justifiable. I'm now making new test plans to benchmark these algorithms

    ReplyDelete
  7. dude, O(mn) aka findIntersectionMethod2 yields the best performance? come on, that cannot be true!

    ReplyDelete
  8. Java:
    Arrays.asList({1, 1, 2, 4, 4, 7, 8, 8, 9, 14, 14, 20, 20, 20}).retainAll(Arrays.asList({1, 2, 8, 20}));

    Ruby:
    [1, 1, 2, 4, 4, 7, 8, 8, 9, 14, 14, 20, 20, 20] - [1, 1, 1, 2, 2, 8, 8, 20]

    Ruby > Java.

    ReplyDelete
  9. Thank you for the feedback, Santosh.

    ReplyDelete