This should be a simple algorithm but I can't wrap my head around the logic. I need to take 2 arrays and keep only the values that are found in one array or the other and not both.
For example if I have
arr1 [1,2,3,6]
arr2 [2,3,4,5,7]
I want to have 2 arrays again being
arr1 [1,6]
arr2 [4,5,7]
EDIT:
I removed my old code and put in some other working code. Still not very pretty but at least working. All I would need to do is store arr3 into arr1 and arr4 into arr2.
var arr3 = [];
var arr4 = [];
var foundMatch = false;
//find all arr1 elements that don't match arr2 elements
//store into arr4
for(var i=0; i<arr1.length; i++)
{
foundMatch = false;
for(var j=0; j<arr2.length; j++)
{
if(arr1[i] == arr2[j])
{
console.log("match found for [%s] [%s]", i, j);
foundMatch = true;
break;
}
}
if(!foundMatch)
{
arr4.push(arr1[i]);
}
}
//find all arr2 elements not in arr1
//store in arr3
for(var i=0; i<arr2.length; i++)
{
foundMatch = false;
for(var j=0; j<arr1.length; j++)
{
if(arr2[i] == arr1[j])
{
console.log("match found for [%s] [%s]", i, j);
foundMatch = true;
break;
}
}
if(!foundMatch)
{
arr3.push(arr2[i]);
}
}
The fastest solution in terms of time complexity is to create a Set
or a hash
from one array -> O(N)
, then iterate through the other to compare if an element is not the set -> O(M)
-> and then add it to the diffs array.
The main benefit here is that Set lookup time is constant.
This solution also has space complexity of O(N)
for building the set.
You can repeat this for the other array as well, giving you total of O(N) + O(M) + O(N) + O(M)
which, when constant factors are removed, is just O(N+M)
time complexity.
Building the set for the second array gives total space complexity as O(N+M)
.
// Total complexity
// Time: O(N+M)
// Space: O(N+M)
// time complexities for each step shown bellow
let N = [1,2,3,6]
let M = [2,3,4,5,7]
const setForN = new Set(N); // O(N)
const setForM = new Set(M); // O(M)
// O(N + M) at this point
const answerN = N.filter(n => !setForM.has(n)) // O(N)
const answerM = M.filter(m => !setForN.has(m)) // O(M)
// O(N + M) + O(N + M) at this point, which is just O(N + M)
console.log(answerN, answerM);
ES5 solution:
var N = [1,2,3,6]
var M = [2,3,4,5,7]
var setOfNumbers = function(arr) {
return arr.reduce(function(set, item) {
return Object.defineProperty(set, item, { value: item });
}, Object.create(null));
}
var setForN = setOfNumbers(N);
var setForM = setOfNumbers(M);
var answerN = N.filter(function(n) { return typeof setForM[n] !== 'number' });
var answerM = M.filter(function(m) { return typeof setForN[m] !== 'number' });
console.log(answerN, answerM);
Another way is to do what other answers suggest which is to, for each element in N
-> O(N)
, check if it exists in M
-> O(M)
, and add it to the diffs array. Repeat for the other array.
This has better, constant, space complexity O(1)
but slower quadratic O(N*M)
time.
// Total Complexity:
// Time: O(N*M)
// Space: O(1)
let N = [1,2,3,6]
let M = [2,3,4,5,7]
// For every element in N -> O(N)
// Iterate through M and check if it's there -> O(M)
// Total: O(N*M)
const answerN = N.filter(n => !M.includes(n));
// For every element in M -> O(M)
// Iterate through N and check if it's there -> O(N)
// Total: O(M*N)
const answerM = M.filter(m => !N.includes(m));
// O(N*M) + O(M*N) at this point, which is just O(N*M)
console.log(answerN, answerM);