The simplest solution would be to use sets, as long as you don't care that the elements in the result will have a different order, and that duplicates will be removed. The input arrays array1 and array2 are the Integer[] subarrays of the given int[] arrays corresponding to the number of elements that you intend to process:
Set<Integer> s1 = new HashSet<Integer>(Arrays.asList(array1));
Set<Integer> s2 = new HashSet<Integer>(Arrays.asList(array2));
s1.retainAll(s2);
Integer[] result = s1.toArray(new Integer[s1.size()]);
The above will return an Integer[], if needed it's simple to copy and convert its contents into an int[].
The simplest solution would be to use sets, as long as you don't care that the elements in the result will have a different order, and that duplicates will be removed. The input arrays array1 and array2 are the Integer[] subarrays of the given int[] arrays corresponding to the number of elements that you intend to process:
Set<Integer> s1 = new HashSet<Integer>(Arrays.asList(array1));
Set<Integer> s2 = new HashSet<Integer>(Arrays.asList(array2));
s1.retainAll(s2);
Integer[] result = s1.toArray(new Integer[s1.size()]);
The above will return an Integer[], if needed it's simple to copy and convert its contents into an int[].
If you are fine with java-8, then the simplest solution I can think of is using streams and filter. An implementation is as follows:
public static int[] intersection(int[] a, int[] b) {
return Arrays.stream(a)
.distinct()
.filter(x -> Arrays.stream(b).anyMatch(y -> y == x))
.toArray();
}
foreach element e in array A
insert e into hash table H
foreach element e in array B
if H contains e
print e
This algorithm is O(N) in time and O(N) in space.
To avoid the extra space, you can use the sorting based approach.
The lower bound on efficiency is O(n) - you need to at least read all the elements. Then there are several apporaches:
Dumb simplest approach
Search for every element from array one in array two. Time complexity O(n^2).
Sorting approach
You need to sort only array one, then search for elements from array two using binary search. Time complexity: sorting O(nlogn), searching O(n * logn) = O(nlogn), total O(nlogn).
Hash approach
Create a hash table from array one elements. Search for elements form second table in the hash table. The time complexity depends on the hash function. You can achieve O(1) for searches in the optimal case (all elements will have different hash value), but O(n) in the worst case (all elements will have the same hash value). Total time complexity: O(n^x), where x is a factor of hash function efficiency (between 1 and 2).
Some hash functions are guaranteed to build a table with no collisions. But the building no longer takes strictly O(1) time for every element. It will be O(1) in most cases, but if the table is full or a collision is encountered, then the table needs to be rehashed - taking O(n) time. This happens not so often, much less frequently than clean adds. So the AMORTISED time complexity is O(1). We don't care about some of the adds taking O(n) time, as long as the majority of adds takes O(1) time.
But even so, in an extreme case, the table must be rehashed every single insertion, so the strict time complexity would be O(n^2)
Algorithm
You're using a O(n log(n)) algorithm here, which could be O(n²) for difficult cases since contains() is O(n) and is called in a loop. Instead, use the property of HashSet: access is O(1), which means you can achieve this in O(n) time. My algorithm below simply keeps track of what it can add to the result. I can add everything that exists in the first list, but I should not add an item I already added.
See my tested code for my implementation:
public static List<Integer> intersection(List<Integer> a, List<Integer> b){
Set<Integer> canAdd = new HashSet<Integer>(a);
List<Integer> result = new ArrayList<Integer>();
for (int n: b) {
if(first.contains(n)) {
result.add(n);
// we wish to add only one n
canAdd.remove(n);
}
}
return result;
}
Comments on your code
- You should return a
List, not anArrayListsince it's an implementation detail. Using anArrayListis OK here since adding at the end of it has O(1) amortized complexity. Otherwise, lists should beLinkedList(when adding to the beginning, not to the end, as @Landei points out). - Be careful about the names you choose.
findItdoesn't seem to be appropriate, butremoveDuplicatesorintersectiondescribes what the code does.
@Cygal : Assuming that HashSet.contains() is really faster than the List one, this could be the ultimate code :-)
public static List<Integer> intersection(List<Integer> a, List<Integer> b) {
Set<Integer> aSet = new HashSet<Integer>(a);
Set<Integer> bSet = new HashSet<Integer>(b);
for(Iterator<Integer> it = aSet.iterator(); it.hasNext();) {
if(!bSet.contains(it.next())) it.remove();
}
return new ArrayList<Integer>(aSet);
}