22

I have a problem to find common elements in two arrays and that's of different size.

Take , Array A1 of size n and Array A2 of size m, and m != n

So far, I've tried to iterate lists one by one and copy elements to another list. If the element already contains mark it, but I know it's not a good solution.

Mike
  • 47,263
  • 29
  • 113
  • 177
Jijoy
  • 12,386
  • 14
  • 41
  • 48

10 Answers10

39

Sort the arrays. Then iterate through them with two pointers, always advancing the one pointing to the smaller value. When they point to equal values, you have a common value. This will be O(n log n+m log m) where n and m are the sizes of the two lists. It's just like a merge in merge sort, but where you only produce output when the values being pointed to are equal.

def common_elements(a, b):
  a.sort()
  b.sort()
  i, j = 0, 0
  common = []
  while i < len(a) and j < len(b):
    if a[i] == b[j]:
      common.append(a[i])
      i += 1
      j += 1
    elif a[i] < b[j]:
      i += 1
    else:
      j += 1
  return common

print 'Common values:', ', '.join(map(str, common_elements([1, 2, 4, 8], [1, 4, 9])))

outputs

Common values: 1, 4

If the elements aren't comparable, throw the elements from one list into a hashmap and check the elements in the second list against the hashmap.

Downgoat
  • 13,771
  • 5
  • 46
  • 69
moinudin
  • 134,091
  • 45
  • 190
  • 216
  • hm, What would the output be in case it was `[1,1,1,2,2,4]` and `[1,1,1,2,2,2,5]` ? If I read correct shouldn't you also check if it already exists in `common` ? unless you clean up the duplicates in `common_elements` later in your code. –  Dec 25 '10 at 09:24
  • 2
    @Muggen 1, 1, 1, 2, 2. If you want the output to be distinct values, add a `while i < len(a) and j < len(b) and a[i] == b[j]:` before incrementing `i` and `j`. – moinudin Dec 25 '10 at 09:27
  • Nice. +1. What language is that btw ? –  Dec 25 '10 at 09:42
  • 17
    This is order (mlog m + nlog n) not m+n, since you are sorting both arrays. – PrasannaK Sep 03 '12 at 09:14
  • Its not actually m log m + n log n, you only sort each array once not for each item. It is thus correct to say it is O(m + n) because the lower order terms are dropped. – Colin Jack Jul 25 '13 at 13:13
  • 2
    sorting both arrays is mlogm and nlogn as well as m + n for your algorithm so it is O(mlogm + nlogn + m + n) so it is overall O(nlogn) – slashdottir May 29 '14 at 21:00
  • Could use a hash table for O(n + m) algorithm, but that would be O(n) memory – Bao Thai Mar 07 '17 at 22:00
21

If you want to make it efficient I would convert the smaller array into a hashset and then iterate the larger array and check whether the current element was contained in the hashset. The hash function is efficient compared to sorting arrays. Sorting arrays is expensive.

Here's my sample code

import java.util.*;
public class CountTest {     
    public static void main(String... args) {        
        Integer[] array1 = {9, 4, 6, 2, 10, 10};
        Integer[] array2 = {14, 3, 6, 9, 10, 15, 17, 9};                    
        Set hashSet = new HashSet(Arrays.asList(array1)); 
        Set commonElements = new HashSet();        
        for (int i = 0; i < array2.length; i++) {
            if (hashSet.contains(array2[i])) {
                commonElements.add(array2[i]);
            }
        }
        System.out.println("Common elements " + commonElements);
    }    
}

Output:

Common elements [6, 9, 10]

Jacorb Effect
  • 211
  • 2
  • 2
2

In APL:

∪A1∩A2

example:

      A1←9, 4, 6, 2, 10, 10
      A1
9 4 6 2 10 10

      A2←14, 3, 6, 9, 10, 15, 17, 9
      A2
14 3 6 9 10 15 17 9

      A1∩A2
9 6 10 10
      ∪A1∩A2
9 6 10 
StackPC
  • 36
  • 2
2

Throw your A2 array into a HashSet, then iterate through A1; if the current element is in the set, it's a common element. This takes O(m + n) time and O(min(m, n)) space.

V.Reeve
  • 53
  • 6
0

I solve the problem by using Set intersection. It is very elegant. Even though I did not analyze the time complexity, it is probably in reasonable range.

public Set FindCommonElements(Integer[] first, Integer[] second)
{

    Set<Integer> set1=new HashSet<Integer>(Arrays.asList(first));
    Set<Integer> set2=new HashSet<Integer>(Arrays.asList(second));

    // finds intersecting elements in two sets
    set1.retainAll(set2);

    return set1;

}
alan turing
  • 463
  • 4
  • 20
0

Looks like nested loops:

commons = empty
for each element a1 in A1
   for each element a2 in A2
      if a1 == a2
         commons.add(a1)

Schouldn't matter at all if the arrays have the same size.

Depending on the language and framework used, set operations might come in handy.

Eiko
  • 25,601
  • 15
  • 56
  • 71
  • 3
    It's actually O(n*m), witch m and n being the sizes of the arrays. Of course, if you know something about the elements faster algorithms might pop up (i.e. if they contain limited range integers or are sorted). – Eiko Dec 25 '10 at 09:21
  • I'm not a downvoter, but it can be done in O(n log n + m log m) and your approach is O(m * n) which is not good. – Saeed Amiri Dec 28 '10 at 12:25
  • 3
    Sorry, this is nonsense. It wasn't asked for the fastest implementation at all. And with many real-world small-size applications, this easy tight O(m*n) implementation will be faster than the other approaches. And it's low-maintainance code, too. If there are more constraints to consider, we need to know them. Also, it's not clear if sorting the arrays is allowed at all (or copying is possible). – Eiko Dec 28 '10 at 14:20
0

Try heapifying both arrays followed by a merge to find the intersection.

Java example:

public static <E extends Comparable<E>>List<E> intersection(Collection<E> c1,
                                                            Collection<E> c2) {
    List<E> result = new ArrayList<E>();
    PriorityQueue<E> q1 = new PriorityQueue<E>(c1),
                     q2 = new PriorityQueue<E>(c2);
    while (! (q1.isEmpty() || q2.isEmpty())) {
        E e1 = q1.peek(), e2 = q2.peek();
        int c = e1.compareTo(e2);
        if (c == 0) result.add(e1);
        if (c <= 0) q1.remove();
        if (c >= 0) q2.remove();
    }
    return result;
}

See this question for more examples of merging.

Community
  • 1
  • 1
finnw
  • 47,861
  • 24
  • 143
  • 221
  • nitpicking, but it should be `if(c < 0)` and `if (c > 0)` and also add `else`, otherwise you're evaluating the all 3 conditions EVERY time. – st0le Dec 25 '10 at 15:22
  • @st0le, if `c == 0` then all three statements must be executed, otherwise it will go into an infinite loop comparing the same elements over and over again. You can reduce the number of branches at the cost of duplicating the calls to `remove`. – finnw Dec 25 '10 at 15:37
0

The Complexity of what I give is O(N*M + N).

Also note that it is Pseudocode C And that it provides distinct values.

eg.[1,1,1,2,2,4] and [1,1,1,2,2,2,5] Will return [1,2]

The Complexity is N*M cause of the for loops

+ N cause of the checking if it already exists in the ArrayCommon[] (which is n size in case Array2[] contains data which duplicate Part of the Array1[] Assuming N is the size of the smaller Array (N < M).

int Array1[m] = { Whatever };
int Array2[n] = { Whatever };
int ArrayCommon[n] = { };

void AddToCommon(int data)
{
    //How many commons we got so far?
    static int pos = 0; 
    bool found = false;
    for(int i = 0 ; i <= pos ; i++)
    {
        //Already found it?
        if(ArrayCommon[i] == data)
        {
            found = true;
        }
    }
    if(!found)
    {
        //Add it
        ArrayCommon[pos] = data;
        pos++;
    }
}

for(int i = 0 ; i < m ; i++)
{
    for(int j = 0 ; j < n ; j++)
    {
        //Found a Common Element!
        if(Array1[i] == Array2[j])
            AddToCommon(Array1[i]);
    }
}
0

In Python, you would write set(A1).intersection(A2). This is the optimal O(n + m).

There's ambiguity in your question though. What's the result of A1=[0, 0], A2=[0, 0, 0]? There's reasonable interpretations of your question that give 1, 2, 3, or 6 results in the final array - which does your situation require?

  • 2
    @Saaed A hashed-based set implementation will give O(n + m) complexity. –  Dec 26 '10 at 20:17
-2
class SortedArr

    def findCommon(a,b)

      j =0
      i =0
      l1=a.length
      l2=b.length

      if(l1 > l2)
            len=l1
      else
            len=l2
      end


     while i < len
          if a[i].to_i > b[j].to_i
              j +=1
          elsif a[i].to_i < b[j].to_i
              i +=1
          else   
              puts a[i] # OR store it in other ds
              i +=1
              j +=1
          end
     end
  end
end

 t = SortedArr.new
 t.findCommon([1,2,3,4,6,9,11,15],[1,2,3,4,5,12,15])
  • 2
    Please do not leave code only answers. They are of no benefit without explanation. Also, you are answering a question that has been solved for over 2 years. What do you feel like you are adding? – Nick Freeman Jun 12 '13 at 02:46
  • Sorry Nick! This is my first time here. Will keep that in mind. I just wanted to add a Ruby based sol. But anyways will be more careful. – user2476720 Jun 12 '13 at 14:40