Bloomberg LP Interview Question
Software Engineer / DevelopersCountry: United States
Interview Type: Phone Interview
For (2) you could also implement a table of lists where for each value, you enter the array names into the corresponding list. Then any value with 5 elements in them has occurred in all arrays.
Here is the code for your 2nd solution
#pragma warning(disable:4996)
#include <iostream>
#include <vector>
#include <unordered_set>
#include <unordered_map>
#include <algorithm>
#include <cassert>
using namespace std;
auto find_commons = [](const vector<vector<int>>& data) {
unordered_set<int> prev_commons{ data[0].begin(), data[0].end() };
unordered_set<int> cur_commons;
for (size_t i = 1; i < data.size(); ++i) {
for (size_t j = 0; j < data[i].size(); ++j) {
if (prev_commons.find(data[i][j]) != prev_commons.end()) {
cur_commons.insert(data[i][j]);
}
}
cur_commons.swap(prev_commons);
cur_commons.clear();
}
return vector<int>{prev_commons.begin(), prev_commons.end()};
};
int main() {
vector<vector<int>> data = {
{ 1, 2, 3, 4, 5, 6 },
{ 2, 3, 4, 5, 6, 7 },
{ 3, 4, 5, 6, 7, 8 },
{ 4, 5, 6, 7, 8, 9 },
{ 5, 6, 7, 8, 9, 9 }
};
auto r = find_commons(data);
auto ans = { 5, 6 };
assert(r.size() == 2 && equal(r.begin(), r.end(), ans.begin()));
for (auto e : r) {
cout << e << " ";
}
cout << endl;
}
Another approach would be:
1. Traverse each array and insert the value in the map and if value already exists in the map then update the counter for the same.
2. After all array set is traversed. Traverse the map and check if any data is having count equal to 5 then print that.
Limitation: Make sure the array contains unique values only.
void insertTheDataInMap(std::map<int,int>& mapCounter, int* data, int length)
{
std::map<int,int>::iterator it;
for ( int i = 0; i < length; i++)
{
it = mapCounter.find(data[i]);
if ( it == mapCounter.end() )
{
mapCounter.insert(std::make_pair<int,int>(data[i],0));
}
mapCounter[data[i]] += 1;
}
}
int main()
{
int arr1[] = {7,10,12};
int arr2[] = {8,7,10};
int arr3[] = {7,10,9};
int arr4[] = {13,10,7};
int arr5[] = {6,7,10};
// Insert the whole array in map, if value already exists then increment the counter.
// Later traverse the map and check if count ==5 then print that element.
std::map<int,int> mapCounter;
insertTheDataInMap(mapCounter, arr1, 3);
insertTheDataInMap(mapCounter, arr2, 3);
insertTheDataInMap(mapCounter, arr3, 3);
insertTheDataInMap(mapCounter, arr4, 3);
insertTheDataInMap(mapCounter, arr5, 3);
std::map<int,int>::iterator it;
for ( it = mapCounter.begin(); it != mapCounter.end(); ++it)
{
if ( it->second == 5 )
{
std::cout<<"\t"<<it->first;
}
}
}
In the map value include 2 elements (counter, last_array_that_updated_it). The second value can be used to track which array updated this counter last. Thus we can avoid duplicate values in the same array from updating the value.
Suppose if the array having repeated elements like ::
ex:: int arr1[] = {7,10,10,10,10,10,12};
then ?
Hi Gangadhara,
I already wrote that this limitation of the approach.
"Limitation: Make sure the array contains unique values only."
Hi Ricky, I was wondering why you implemented the approach with the limitation rather than the first one, which also seems cleaner and faster:
//commonElements.cpp
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
int arr0[] = {20, 15, 3, 10, 14, 35, 21, 14};
int arr1[] = {3, 10, 14, 18, 36, 15, 17, 25, 41};
int arr2[] = {12, 10, 37, 10, 15, 3};
int arr3[] = {22, 14, 25, 10, 15, 28, 3};
int arr4[] = {14, 10, 3, 10, 15, 18, 35};
int size[5];
size[0] = sizeof(arr0)/sizeof(int);
size[1] = sizeof(arr1)/sizeof(int);
size[2] = sizeof(arr2)/sizeof(int);
size[3] = sizeof(arr3)/sizeof(int);
size[4] = sizeof(arr4)/sizeof(int);
//initialize pointers to array elements
int* ip[5] = {arr0, arr1, arr2, arr3, arr4};
//sort the arrays
for (int i=0; i < 5; i++)
sort(ip[i], ip[i] + size[i]);
//vector to collect the common elements
vector<int> result;
while( ip[0] < arr0 + size[0]
&& ip[1] < arr1 + size[1]
&& ip[2] < arr2 + size[2]
&& ip[3] < arr3 + size[3]
&& ip[4] < arr4 + size[4])
{
if( *ip[0] == *ip[1]
&& *ip[1] == *ip[2]
&& *ip[2] == *ip[3]
&& *ip[3] == *ip[4])
{
result.push_back(*ip[0]);
for (int i=0; i < 5; i++)
{
ip[i]++;
goto endWhile;
}
}
//move up the pointer
//when the element can't be common
for (int i=0; i < 4; i++)
{
if(*ip[i] != *ip[i+1])
{
if(*ip[i+1] < *ip[i])
ip[i+1]++;
else
ip[i]++;
goto endWhile;
}
};
endWhile:;
}
for (int i=0; i < result.size(); i++)
{
cout << result[i] << " ";
}
cout << endl;
}
public static void main()
{
int[] arr1;
int[] arr2;
int[] arr2;
int[] arr4;
int[] arr5;
int[] arrs = {arr1,arr2,arr3,arr4,arr5};
HashTable table1 = new HashTable();
HashTable table2 = new HashTable();
int[] temp1 = arr2;
for (int i=0; i<arr1.length; i++)
{
table1.add(arr1[i],true);
}
for (int i =1; i<4; i++)
{
for(int b=0; b<temp1.length; b++)
{
if (table1.ContainsKey(temp1[i]))
table2.add(temp1[i],true);
}
table1= table2;
table2= new HashTable();
temp1 = arrs[i];
}
}
this runs in O(N) time,
public class common {
public static void main(String args[]){
int arr1[]={1,2,3,4,5,6,7,8,10,12,100};
int arr2[]={2,4,6,8,29,39,44};
int k=0;int arr3[]=new int[4];
for(int i=0;i<arr1.length;i++){
for(int j=0;j<arr2.length;j++){
if(arr1[i]==arr2[j]){
arr3[k]=arr1[i];
k++;
}
}
//This is comparing two arrays it can be extended here
}
for(k=0;k<arr3.length;k++)
System.out.println(arr3[k]);
}
}
Runs in O(n).
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class CommonElements {
public static void insertArray(int arr[],TreeMap<Integer,Integer> mp){
int i =0;
while(i < arr.length){
int var = arr[i];
int a;
if(mp.containsKey(var)){
a = mp.get(var)+1;
mp.put(var, a);
}
else{
mp.put(var, 1);
}
i++;
}
}
public static void main(String[] args) {
int arr1[] = {7,10,12};
int arr2[] = {8,7,10};
int arr3[] = {7,10,9};
int arr4[] = {13,10,7};
int arr5[] = {6,7,10};
TreeMap<Integer,Integer> mp = new TreeMap<Integer,Integer>();
insertArray(arr1,mp);
insertArray(arr2,mp);
insertArray(arr3,mp);
insertArray(arr4,mp);
insertArray(arr5,mp);
Set set = mp.entrySet();
Iterator i = set.iterator();
while(i.hasNext()){
Map.Entry me = (Map.Entry)i.next();
int key = (Integer) me.getKey();
int value = (Integer)me.getValue();
if(value == 5){
System.out.println("Number : "+key);
}
}
}
}
1. Compare the smallest array with the next smaller array.
2. Find the common elements and store them in a new array say common array .
3. Then compare the remaining arrays (sequentially) , with the common array to find out the common elements.
4.During each array comparison update the common array accordingly by deleting the uncommon elements.
5. Then compare the rest of the arrays.
Common array contains the desired result.
Groovy Code but the limitation with the code is the arrays cannot have duplicates
def repatingElementsInArrayLists(Object[] args)
{
completeList=[]
map = [:]
for(arg in args)
{
arg.each {
entry = map.find{n,count -> n == it}
if(entry == null) { map.put(it,1) }
else { entry.value++}
}
}
repatListMap = map.findAll{num,count->count==args.size()}
repatListMap.each { entry -> println "$entry.key"}
}
repatingElementsInArrayLists([1,2,4,5],[2,5,6],[1,2,3,5])
Groovy Code but the limitation with the code is the arrays cannot have duplicates
def repatingElementsInArrayLists(Object[] args)
{
completeList=[]
map = [:]
for(arg in args)
{
arg.each {
entry = map.find{n,count -> n == it}
if(entry == null) { map.put(it,1) }
else { entry.value++}
}
}
repatListMap = map.findAll{num,count->count==args.size()}
repatListMap.each { entry -> println "$entry.key"}
}
repatingElementsInArrayLists([1,2,4,5],[2,5,6],[1,2,3,5])
public class CommonElements {
public static void main(String[] args) {
HashMap<Integer,Integer> table = new HashMap<Integer,Integer>();
int[] a1 = {1,2,3,4,5};
int[] a2 = {2,3,5,1,9};
int[] a3 = {3,4,1,2,5};
int[] a4 = {9,7,6,7,3};
int[] a5 = {3,2,1,5,8};
int i =0;
for (i=0;i<a1.length;i++)
table.put(a1[i],1);
for (i=0;i<a2.length;i++)
if(table.get(a2[i]) != null)
table.put(a2[i],(table.get(a2[i])+1));
for (i=0;i<a3.length;i++)
if(table.get(a3[i]) != null)
table.put(a3[i],(table.get(a3[i])+1));
for (i=0;i<a4.length;i++)
if(table.get(a4[i]) != null)
table.put(a4[i],(table.get(a4[i])+1));
for (i=0;i<a5.length;i++)
if(table.get(a5[i]) != null)
table.put(a5[i],(table.get(a5[i])+1));
Set set = table.entrySet();
Iterator ii = set.iterator();
while(ii.hasNext()){
Map.Entry me = (Map.Entry)ii.next();
int key = (Integer) me.getKey();
int value = (Integer)me.getValue();
if(value == 5){
System.out.println("Number : "+key);
}
}
}
}
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <iterator>
using namespace std;
int main() {
int arr1[] = {1,2,3,4,5,6,7,8,9,10};
int arr2[] = { 2,3,4,5,6,7,8,9,10,11};
int arr3[] = { 3,4,5,6,7,8,9,10,11,12};
int arr4[] = { 4,5,6,7,8,9,10,11,12,13};
int arr5[] = { 5,6,7,8,9,10,11,12,13,14};
const size_t arr1_size = sizeof(arr1)/sizeof(int);
const size_t arr2_size = sizeof(arr2)/sizeof(int);
const size_t arr3_size = sizeof(arr3)/sizeof(int);
const size_t arr4_size = sizeof(arr4)/sizeof(int);
const size_t arr5_size = sizeof(arr5)/sizeof(int);
string l1 = "arr1";
string l2 = "arr2";
string l3 = "arr3";
string l4 = "arr4";
string l5 = "arr5";
map<int, set<string> > m;
for (int i=0; i < arr1_size; ++i) {
m[arr1[i]].insert(l1);
}
for (int i=0; i < arr2_size; ++i) {
m[arr2[i]].insert(l2);
}
for (int i=0; i < arr3_size; ++i) {
m[arr3[i]].insert(l3);
}
for (int i=0; i < arr4_size; ++i) {
m[arr4[i]].insert(l4);
}
for (int i=0; i < arr5_size; ++i) {
m[arr5[i]].insert(l5);
}
map<int, set<string> >::const_iterator it = m.begin();
map<int, set<string> >::const_iterator end = m.end();
for (; it != end; ++it) {
if (it->second.size() == 5) // set contains all 5 labels
{
cout << it->first << endl;
}
}
return 0;
}
Following code has no limitation in terms duplicates. Also it can find common elements in any number of arrays, not only five. However, its time complexity is not very good because of retainAll method. It is very clean solution though. If there is no time constraints this could be a good solution.
import java.util.HashSet;
import java.util.ArrayList;
public class FindCommonElements {
public HashSet<Integer> findCommons(ArrayList<int[]> listOfElemens){
HashSet<Integer> set=new HashSet<Integer>();
int[] firstList=listOfElemens.get(0);
for(int i: firstList)
set.add(i);
for(int[] list: listOfElemens){
HashSet<Integer> tempSet=new HashSet<>();
for(int i: list)
tempSet.add(i);
//finds intersection of two sets
set.retainAll(tempSet);
}
return set;
}
public static void main(String[] args){
int arr1[] = {7,10,12,5,5};
int arr2[] = {8,7,10,5,5};
int arr3[] = {7,10,9,5,5};
int arr4[] = {13,10,7,5,5};
int arr5[] = {6,7,7,5,5,10};
ArrayList<int[]> listOrArrs=new ArrayList<>();
listOrArrs.add(arr1);
listOrArrs.add(arr2);
listOrArrs.add(arr3);
listOrArrs.add(arr4);
listOrArrs.add(arr5);
FindCommonElements fce=new FindCommonElements();
HashSet<Integer> set=fce.findCommons(listOrArrs);
System.out.print(set);
}
}
Another O(N) approach using hash map and bitset. While scanning the each element in each array, turn on the corresponding bit position in the hash map's value, bitset. If all bits are on, that element exist in all arrays.
auto find_commons2 = [](const vector<vector<int>>& data) {
unordered_map<int, bitset<5>> commons;
for (size_t i = 0; i < 5; ++i) {
for (size_t j = 0; j < data[i].size(); ++j) {
commons[data[i][j]].set(i);
}
}
vector<int> ret;
for (auto& p : commons) {
if (p.second.all()) {
ret.push_back(p.first);
}
}
return ret;
};
void checkcommo(int *a, int*b, int *c, int *d, int *e, int n){
int check[200] = {0}; //say numbers were between 0-199
for(int i = 0; i<5; i++){
if(check[a[i]] == 0){
check[a[i]] =1;
}
}
for(int i = 0; i<5; i++){
if(check[b[i]] == 1){
check[b[i]] = 2;
}
}
for(int i = 0; i<5; i++){
if(check[c[i]] == 2){
check[c[i]] = 3;
}
}
for(int i = 0; i<5; i++){
if(check[d[i]] == 3){
check[d[i]] = 4;
}
}
for(int i = 0; i<5; i++){
if(check[e[i]] == 4){
cout<< e[i] << " ";
}
}
}
void checkcommo(int *a, int*b, int *c, int *d, int *e, int n){
int check[200] = {0}; //say numbers were between 0-199
for(int i = 0; i<5; i++){
if(check[a[i]] == 0){
check[a[i]] =1;
}
}
for(int i = 0; i<5; i++){
if(check[b[i]] == 1){
check[b[i]] = 2;
}
}
for(int i = 0; i<5; i++){
if(check[c[i]] == 2){
check[c[i]] = 3;
}
}
for(int i = 0; i<5; i++){
if(check[d[i]] == 3){
check[d[i]] = 4;
}
}
for(int i = 0; i<5; i++){
if(check[e[i]] == 4){
cout<< e[i] << " ";
}
}
}
Simple, O(liner time), memory inefficient solution:
1. Pull each arrays into its own HashSet (s1,s2,s3,s4,s5) --> O(size of array)
2. Use retainAll() function from set --> O(size of array). (Linear time because for a HashSet, time complexity for contains used by retainAll is O(1))
s1.retainAll(s2)
s1.retainAll(s3)
s1.retainAll(s4)
s1.retainAll(s5)
s1 will contain all the common elements
I can think of two approaches:
- Murali Mohan January 30, 20141. Sort all the 5 arrays and 'walk' through them using 5 pointers to 5 arrays to find out the intersection of elements.
2. Use 2 hashsets. Put all the elements of the first array in the first hashset. From the 2nd array onwards, check if the given array element is present in the first hashset, if yes, put it in the second hash set. At the end of the iteration, clear the first hashset and use it for the next iteration.