Hey everyone! Welcome back to Code Review, a series of interview challenges released weekly that are completely free for the community. This week we’ll be working on a common, relatively straightforward question that I personally have been asked multiple times in interviews. I chose this challenge because there are multiple ways to approach the problem, each with various time and space trade-offs.
The Challenge:
Write a function, FindIntersection, that reads an array of strings which will contain two elements: the first element will represent a list of comma-separated numbers sorted in ascending order, the second element will represent a second list of comma-separated numbers (also sorted). Your goal is to return a string of numbers that occur in both elements of the input array in sorted order. If there is no intersection, return the string "false".
For example: if the input array is ["1, 3, 4, 7, 13", "1, 2, 4, 13, 15"] the output string should be "1, 4, 13" because those numbers appear in both strings. The array given will not be empty, and each string inside the array will be of numbers sorted in ascending order and may contain negative numbers.
The Brute Force Solution:
A brute-force solution is to loop over the numbers of the first string, and for each number in the first string, loop over all numbers of the other string, looking for a match. If a match is found, concat that value to a result string.
function FindIntersection (strArr) {
const inBothStrings = []
const arr1 = strArr[0].split(', ')
const arr2 = strArr[1].split(', ')
arr1.forEach(elementArr1 => {
const numArr1 = parseInt(elementArr1)
arr2.forEach(elementArr2 => {
const numArr2 = parseInt(elementArr2)
if (numArr1 === numArr2) {
inBothStrings.push(numArr1)
}
})
})
return inBothStrings.join(',')
}
Although this will work, it is not the most optimal solution. The worst case scenario (if there are no matches) is that for every element in the first string, we will have to iterate through every element in the second string. This has a time complexity of O(nm) where n and m are the size of the given strings.
If you haven’t heard of Big O notation, check out this great article which goes into all the details. Understanding Big O notation and being able to communicate how optimal your solution is to an interviewer is an extremely important part of any technical interview.
Try it Out:
Head on over to Coderbyte and try and solve the problem in a more optimized way. Remember to come back next week where I’ll discuss some other solutions and common pitfalls to this problem. Good luck coding :)
Our newsletter 📫
We’re going to be sending out a small, feature reveal snippet every time we release something big, so our community is the first to know when we break out something new. Give us your email here and we'll add you to our "first to know" list :)
Oldest comments (48)
Thank you!
But
[...s1].filter(x => s2.has(x))is still O(n²), isn't it?I'm pretty sure there is a O(s1) + O(s2) = O(n) solution.
Good answer but you lost the ordering when using sets.
Yes, I've looked up how
Setworks and you're right. Thanks for clarifying.Another cool solution (but not as readable as yours) however is this "destructive" one on SO.
Rust solution - works for any number of strings:
Is there any difference between
and
?
None that I'm aware of. I prefer
"".to_owned()overString::from("")or"".to_string()to avoid the confusion of "why are you converting a string to a string?" that I've seen in some newbie Rust threads.because I'd argue that letting your language work for you, and therefore optimizing developer time, is better than optimizing execution time when not strictly necessary.
When the language solves the problem for you... touché
To follow up: I made three versions of this code. The first version is as above, the second version has the naive approach to finding the intersection:
and a third approach uses a map for lookup:
Performing some timed tests shows that using the built-in function consistently takes about two to three times as long as the self-built map-based function, growing at roughly
O(n)using a random array of size 1000 and 10000. Only in exceptional cases would I not use the built-in function.The naive approach, on the other hand, grows with
O(n²)and takes significantly longer at larger array sizes. However, with 26ms with an array size of 1000, it depends on the use case whether I would start optimizing this (if this isn't easily replaced with a built-in function).Nice work!! Always always interesting to test out a language's built in methods and know whats what when it comes to time complexity.
Nice solution! Love your use of Sets. Very concise and clear.
This is my approach.
Nice custom parseArray function!! And I like that use of Object.entries().
I used for loop so that improve the performance
Clarification question: can the lists have duplicate values?
Good question! Nope, the lists will not have duplicates in themselves.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.