One of the most salient features of our Tech Hiring culture is that there is so much bullshit. Everyone knows this. Each of us contributes his share. But we tend to take the situation for granted.
funmain(){testAnagram("cinema","iceman")testAnagram("algo-trivia","knuth")benchmark()/** OutputAre cinema and iceman anagrams? YesAre algo-trivia and knuth anagrams? NoIt took 1118 milliseconds to sort an array of 1000000 elements**/}funtestAnagram(a:String,b:String){valok=a.toList().sorted()==b.toList().sorted()println("Are $a and $b anagrams? "+if(ok)"Yes"else"No")}funbenchmark(){valarraySize=1_000_000valbigList=List(arraySize){Random.nextInt()}valbenchmark=measureTimeMillis{bigList.sorted()}println("It took $benchmark milliseconds to sort an array of $arraySize elements")}
As you can see, your first intuition was right.
Sorting an array is a bulletproof way to check that two words are an anagram.
Now if we are talking about the price of things, the first solution is the optimal one.
Words are usually very small lists. Even German words.
Let's assume I have alien words of 1 million characters.
That still takes less close to no time at all to sort out.
Who cares? Not the business.
On the other hand, a smart business does not particularly like developers who reinvent wheels.
Such a developer will spend much more than one second reinventing an algorithm for this.
It might be buggy, which means that the business will have to go through the complete lifecycle of having a client report a bug, file a jira ticket, wait that someone is ready, fix it, do a release, announce it.
It's important to udnerstand that your time isn't free and is, in fact, quite expansive.
So a smart business should in my opinion gives it thumbs up to a candidate that use the .sort() function from the standard library.
Front end developer specialising in JavaScript and React. Experienced in all aspects of modern front end development. Passionate about making accessible, secure and performant software.
Good effort, but unfortunately this solution doesn't always work.
E.g. when str1 is aaaaa and str2 is abbbb, it returns true when it should be false.
It's because .includes checks that the letter is anywhere in the string, not caring about how many times. However the number of times the letter appears also needs to match the other string.
Front end developer specialising in JavaScript and React. Experienced in all aspects of modern front end development. Passionate about making accessible, secure and performant software.
That's right. That's what we're testing for: whether they are anagrams of each other. So in the str1 = aaaaa and str2 = abbbb case it should return false because as you say they're not anagrams of each other.
Front end developer specialising in JavaScript and React. Experienced in all aspects of modern front end development. Passionate about making accessible, secure and performant software.
So with the sort function you have O(nlog(n)). Then how about this solution for O(n). You have a dictionary with the char as key, and counter (how many times char appeared) as value. You iterate with a for over both arrays at the same time (O(n)) and each char in the first string adds to that key, while the same char in the second string subtracts. In the end you want to have 0 for all keys:
function anagram(str1, str2){
//Prepare a dictionary to count appearances
const dict = {}
const arr1 = str1.split('');
const arr2 = str2.split('');
// if lenght is different return false, think it's O(1)
if(arr1.length != arr2.length) return false
for(let i = 0; i < str1.length; ++i){
// increase number for keys in arr1 and decrease for keys in arr 2
// if the same, result should be 0 in the end
if(dict[arr1[i]] != undefined){
dict[arr1[i]] = 1
}else{
dict[arr1[i]] += 1
}
if(dict[arr2[i]] != undefined){
dict[arr2[i]] = -1
}else{
dict[arr2[i]] -= 1
}
}
// check the dict
for(let key in dict){
if(dict[key] != 0){
return false;
}
}
// if reatched, it means all keys are 0
return true
}
L.A. based web developer slowly parsing through Stack Overflow. If you like hot web dev tips or stories about being a freelancer, check out my newsletter: https://codenutt.substack.com/p/coming-soon
Hello!
How to check that two words are anagrams?
Should we
If I was on the hiring side, I am not sure I would have choosen a candidate who opt for the second solution and waste its time on algorithm trivia.
Have a look at this snippet and run it from pl.kotl.in/swFfcgRPy
As you can see, your first intuition was right.
Sorting an array is a bulletproof way to check that two words are an anagram.
Now if we are talking about the price of things, the first solution is the optimal one.
Words are usually very small lists. Even German words.
Let's assume I have alien words of 1 million characters.
That still takes less close to no time at all to sort out.
Who cares? Not the business.
On the other hand, a smart business does not particularly like developers who reinvent wheels.
Such a developer will spend much more than one second reinventing an algorithm for this.
It might be buggy, which means that the business will have to go through the complete lifecycle of having a client report a bug, file a jira ticket, wait that someone is ready, fix it, do a release, announce it.
It's important to udnerstand that your time isn't free and is, in fact, quite expansive.
So a smart business should in my opinion gives it thumbs up to a candidate that use the
.sort()function from the standard library.Good effort, but unfortunately this solution doesn't always work.
E.g. when
str1isaaaaaandstr2isabbbb, it returnstruewhen it should be false.It's because
.includeschecks that the letter is anywhere in the string, not caring about how many times. However the number of times the letter appears also needs to match the other string.aaaaaandabbbbis not an anagram in the first place, is it?That's right. That's what we're testing for: whether they are anagrams of each other. So in the
str1 = aaaaaandstr2 = abbbbcase it should returnfalsebecause as you say they're not anagrams of each other.function anagram(str1, str2) {return (
str1.length == str2.length &&
str1.split("").every(c => str2.includes(c)) &&
str2.split("").every(c => str1.includes(c))
);
}
... and its still about 70% faster.
Nice :)
So with the sort function you have
O(nlog(n)). Then how about this solution forO(n). You have a dictionary with the char as key, and counter (how many times char appeared) as value. You iterate with a for over both arrays at the same time(O(n))and each char in the first string adds to that key, while the same char in the second string subtracts. In the end you want to have 0 for all keys:const isAnagram = (str1, str2) =>
[...str1].sort().join("") === [...str2].sort().join("");
That's a great solution. Thanks for sharing!
speaking of free, you overlooked the alloc