Are strings anagram

Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
5
down vote
favorite
This is a question from the book "Cracking the Coding Interview".
Write a method to decide if two strings are anagrams or not
I think interviewer will not be convinced with this solution because here it is no test of logic. Please help me to optimise this solution.
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
std::string toLower(std::string str)
std::transform(str.begin(), str.end(), str.begin(),
(unsigned char ch) return std::tolower(ch); );
return str;
bool areAnagrams(std::string& str1, std::string& str2)
str1 = toLower(str1);
str2 = toLower(str2);
std::sort(str1.begin(), str1.end());
std::sort(str2.begin(), str2.end());
if (str1.compare(str2) == 0)
return true;
else
return false;
int main()
std::string str1, str2;
std::cout << "Enter String 1: ";
std::getline(std::cin, str1);
std::cout << "Enter String 2: ";
std::getline(std::cin, str2);
bool res = areAnagrams(str1, str2);
if (res == 1)
std::cout << "Strings are anagramn";
else
std::cout << "Strings are not anagramn";
c++ programming-challenge interview-questions
add a comment |Â
up vote
5
down vote
favorite
This is a question from the book "Cracking the Coding Interview".
Write a method to decide if two strings are anagrams or not
I think interviewer will not be convinced with this solution because here it is no test of logic. Please help me to optimise this solution.
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
std::string toLower(std::string str)
std::transform(str.begin(), str.end(), str.begin(),
(unsigned char ch) return std::tolower(ch); );
return str;
bool areAnagrams(std::string& str1, std::string& str2)
str1 = toLower(str1);
str2 = toLower(str2);
std::sort(str1.begin(), str1.end());
std::sort(str2.begin(), str2.end());
if (str1.compare(str2) == 0)
return true;
else
return false;
int main()
std::string str1, str2;
std::cout << "Enter String 1: ";
std::getline(std::cin, str1);
std::cout << "Enter String 2: ";
std::getline(std::cin, str2);
bool res = areAnagrams(str1, str2);
if (res == 1)
std::cout << "Strings are anagramn";
else
std::cout << "Strings are not anagramn";
c++ programming-challenge interview-questions
add a comment |Â
up vote
5
down vote
favorite
up vote
5
down vote
favorite
This is a question from the book "Cracking the Coding Interview".
Write a method to decide if two strings are anagrams or not
I think interviewer will not be convinced with this solution because here it is no test of logic. Please help me to optimise this solution.
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
std::string toLower(std::string str)
std::transform(str.begin(), str.end(), str.begin(),
(unsigned char ch) return std::tolower(ch); );
return str;
bool areAnagrams(std::string& str1, std::string& str2)
str1 = toLower(str1);
str2 = toLower(str2);
std::sort(str1.begin(), str1.end());
std::sort(str2.begin(), str2.end());
if (str1.compare(str2) == 0)
return true;
else
return false;
int main()
std::string str1, str2;
std::cout << "Enter String 1: ";
std::getline(std::cin, str1);
std::cout << "Enter String 2: ";
std::getline(std::cin, str2);
bool res = areAnagrams(str1, str2);
if (res == 1)
std::cout << "Strings are anagramn";
else
std::cout << "Strings are not anagramn";
c++ programming-challenge interview-questions
This is a question from the book "Cracking the Coding Interview".
Write a method to decide if two strings are anagrams or not
I think interviewer will not be convinced with this solution because here it is no test of logic. Please help me to optimise this solution.
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
std::string toLower(std::string str)
std::transform(str.begin(), str.end(), str.begin(),
(unsigned char ch) return std::tolower(ch); );
return str;
bool areAnagrams(std::string& str1, std::string& str2)
str1 = toLower(str1);
str2 = toLower(str2);
std::sort(str1.begin(), str1.end());
std::sort(str2.begin(), str2.end());
if (str1.compare(str2) == 0)
return true;
else
return false;
int main()
std::string str1, str2;
std::cout << "Enter String 1: ";
std::getline(std::cin, str1);
std::cout << "Enter String 2: ";
std::getline(std::cin, str2);
bool res = areAnagrams(str1, str2);
if (res == 1)
std::cout << "Strings are anagramn";
else
std::cout << "Strings are not anagramn";
c++ programming-challenge interview-questions
asked Aug 2 at 17:02
coder
911425
911425
add a comment |Â
add a comment |Â
3 Answers
3
active
oldest
votes
up vote
12
down vote
accepted
I think interviewer will not be convinced with this solution because here it is no test of logic.
I'm not sure what you mean by "because here it is no test of logic," but if what you mean is "because I found this puzzle too easy," then good! That's what the interviewer is likely to be hiring for: people who solve problems easily and quickly.
When you get an easy problem in an interview, that may be a sign that the interviewer is trying to judge your coding skills rather than your algorithmic/research skills. So make sure your code is as polished as (reasonably) possible.
areAnagramstakes its parameters by non-const reference. This is probably a bug. The interviewer will ask you to "explain your choice." Your answer should be something like "oops, I forgot to remove the&." (This reflects a little badly on your coding skills.)if (res == 1)is a very strange way to test for booleantrue-ness. It would be less unusual, but still a minor yellow flag, to test forif (res == true)orif (res). It would be good to remove the useless variable and test directly forif (areAnagrams(str1, str2)).
Similarly, in the body of areAnagrams, you have written
if (str1.compare(str2) == 0)
return true;
else
return false;
This is a very long-winded and confusing way of writing
return str1 == str2;
and is kind of a big deal. The interviewer is not looking to hire people who write eight lines of convoluted code when one line of simple code would do the job.
You also have an extra blank line at the beginning of areAnagrams; this shows a possible tendency toward sloppiness. The interviewer is not looking to hire people who might "typo" their way into a bug.
On the plus side, your definition of toLower is very good! The interviewer might ask you to explain why you took by value instead of by const&. The interviewer might ask you whether the line return str; makes a copy of the string or whether the copy is elided. (Trick question! The answer is "neither.")
The answer is "neither."Why does NRVO not work in this case?
â yuri
Aug 2 at 20:22
4
Funny you should ask! NRVO works by constructing the objectstrdirectly intotoLower's return slot. But in this case,toLowerdoes not control wherestrgets constructed (becausestris a parameter). The result is thatstrwill be moved into the return slot â neither copied nor copy-elided, but moved.
â Quuxplusone
Aug 2 at 23:07
add a comment |Â
up vote
9
down vote
I see some things that may help you improve your code.
bool is not int
The bool type is a full-fledged first class type in C++. If I were an interviewer reading this code, I'd be perplexed:
bool res = areAnagrams(str1, str2);
if (res == 1)
std::cout << "Strings are anagramn";
else
std::cout << "Strings are not anagramn";
A similar thing is being done here:
if (str1.compare(str2) == 0)
return true;
else
return false;
First, we are comparing a bool to 1 (an int) which is odd enough. Next, if we're returning the result of the comparison, why don't we return the result of the comparison?
return !str1.compare(str2);
Better still:
return str1 == str2;
Understand references
The prototype of the toLower function is this:
std::string toLower(std::string str);
bool areAnagrams(std::string& str1, std::string& str2);
So reading this, the toLower makes a copy of its argument and areAnagrams uses references. However, the first few lines of the latter function are these:
str1 = toLower(str1);
str2 = toLower(str2);
There's little point to making copies and then assigning the copy back to the original. What I would recommend instead is to have toLower take a reference and areAnagrams pass by value. That way, we have a much more logical interface in which toLower modifies the passed string but areAnagrams does not.
Use auto to simplify code
The better choice for res in main would be to declare it auto instead of explicitly naming bool.
Consider the use of locale
Rather than writing your own toLower, why not use the one in <locale>? Here's how that might look:
auto& facetstd::use_facet<std::ctype<char>>(std::locale());
facet.tolower(&str1.front(), &str1.back());
facet.tolower(&str2.front(), &str2.back());
Use better naming
The function toLower is a good name because (with the suggested change mentioned above) it says what it actually does. However, res is not a good name and it's not necessary to have a separate variable anyway. Instead of this strange construction:
bool res = areAnagrams(str1, str2);
if (res == 1)
std::cout << "Strings are anagramn";
else
std::cout << "Strings are not anagramn";
I would probably instead have written this:
std::cout << "Strings " << (areAnagrams(str1, str2) ? "are" : "are not")
<< " anagramsn";
Although, as @TobySpeight points out in a comment, better for the purposes of translating the string into another language would be to keep the strings intact. One way to do that:
std::cout << (areAnagrams(str1, str2) ? "Strings are anagramsn"
: "Strings are not anagramsn");
Declare variables each on a separate line
Clarify variable declaration by declaring each one on a single line. See Guideline ES.10
Consider namespace or static
During an interview, I'd probably ask why you chose not to encapsulate the functions in a namespace, and why the functions are not static. There are arguments both ways for each of those; be aware of what they are and be able to explain and defend your choices.
std::string::comparereturns <0, 0, or >0, so the first part of your answer doesn't make any sense.
â jamesdlin
Aug 2 at 22:25
@jamesdlin: it was missing a!which is now corrected.
â Edward
Aug 2 at 22:47
3
I meant that the whole "boolis notint" premise is misdirected ("we are comparing aboolto0..."; no, it's comparingintto0). Regarding your edit: I personally dislike!str.compare(str)for the same reason as you originally give:boolis notint, and!on anintseems weird.
â jamesdlin
Aug 2 at 22:55
1
First, withinmainwe haveif (res == 1)which is comparing aboolto anint. Second, I agree that!str1.compare(str2)is not very good, which is why what I recommend instead isreturn str1 == str2;which I suspect we both agree is the most clear and straightforward way to do it.
â Edward
Aug 2 at 23:12
2
Under "Use better naming", you go a bit further than I would. There's an argument against breaking strings into pieces like that - it's an anti-pattern that hinders translation. When your program is likely to be translated (and in an interview you do want to demonstrate that you can work with translators), it's usually better to keep strings whole - this is where C-style format strings can be valuable:std::printf(areAnagrams(str1, str2) ? "%s is an anagram of %sn" : "%s is not an anagram of %sn", str1.c_str(), str2.c_str());
â Toby Speight
Aug 3 at 7:59
 |Â
show 2 more comments
up vote
2
down vote
You know, when deciding whether you have anagrams, you are generally only interested in alpha-numeric characters, the rest are disregarded.
Next, making extraneous copies is generally a bad idea. So, accept a constant view and don't make a copy.
When you accept a mutable reference, be sure that it's obvious from the function-name and arity that it's a mutable reference.
If you can, avoid external linkage. It promotes inlining and avoids unfortunate name-clashes.
Finally, a faster algorithm is normally preferable:
bool isAnagram(std::string_view a, std::string_view b) noexcept
unsigned counts[1ULL + (unsigned char)-1] = ;
for (unsigned char c : a)
++counts[std::tolower(c)];
for (unsigned char c : b)
--counts[std::tolower(c)];
for (std::size_t i = 0; i < std::size(counts); ++i)
if (counts[i] && std::isalnum(i))
return false;
return true;
3
While this may be a faster algorithm, is it a clearer algorithm? I think that for an interview, it may be better to write for clarity.
â Edward
Aug 2 at 18:21
@Edward Yes, I would say so.
â Deduplicator
Aug 2 at 18:49
(2) This code is different from OP's, it ignores non-alnum characters. (3) It's actually slower for short string, as it allocates an array of ~256 ints.
â user176443
Aug 3 at 3:56
Whyint map?unsigned mapwill likely give the right answer in most cases for extremely long strings even if a bucket wraps around, without any signed-overflow UB. (If you can rule out long strings,unsigned char mapcuts the cache footprint by 4 on most modern C++ implementations, and allows faster checking for non-zero buckets on targets where the compiler can use SIMD for the final loop.) I was going to sayuint8_t, but you don't need to stop the code from working on implementations without uint8_t, like some DSPs where char is 32 bits.
â Peter Cordes
Aug 3 at 8:10
1
@user17... If you're checking all characters, then check if lengths are equal as an early-out before doing anything else. But allocating 1kiB on the stack is basically free; literally 1 instruction. Zeroing it has some small cost. Touching it might cause some cache misses, but store-forwarding might manage to hide a lot of the cost of that (i.e. the reloads don't have to wait for the stores to commit); only 32x 32-byte stores, so maybe 32 store-buffer entries for zeroing it. The load part of each increment should forward from the zeroing, but the store part uses another buffer.
â Peter Cordes
Aug 3 at 11:14
 |Â
show 3 more comments
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
12
down vote
accepted
I think interviewer will not be convinced with this solution because here it is no test of logic.
I'm not sure what you mean by "because here it is no test of logic," but if what you mean is "because I found this puzzle too easy," then good! That's what the interviewer is likely to be hiring for: people who solve problems easily and quickly.
When you get an easy problem in an interview, that may be a sign that the interviewer is trying to judge your coding skills rather than your algorithmic/research skills. So make sure your code is as polished as (reasonably) possible.
areAnagramstakes its parameters by non-const reference. This is probably a bug. The interviewer will ask you to "explain your choice." Your answer should be something like "oops, I forgot to remove the&." (This reflects a little badly on your coding skills.)if (res == 1)is a very strange way to test for booleantrue-ness. It would be less unusual, but still a minor yellow flag, to test forif (res == true)orif (res). It would be good to remove the useless variable and test directly forif (areAnagrams(str1, str2)).
Similarly, in the body of areAnagrams, you have written
if (str1.compare(str2) == 0)
return true;
else
return false;
This is a very long-winded and confusing way of writing
return str1 == str2;
and is kind of a big deal. The interviewer is not looking to hire people who write eight lines of convoluted code when one line of simple code would do the job.
You also have an extra blank line at the beginning of areAnagrams; this shows a possible tendency toward sloppiness. The interviewer is not looking to hire people who might "typo" their way into a bug.
On the plus side, your definition of toLower is very good! The interviewer might ask you to explain why you took by value instead of by const&. The interviewer might ask you whether the line return str; makes a copy of the string or whether the copy is elided. (Trick question! The answer is "neither.")
The answer is "neither."Why does NRVO not work in this case?
â yuri
Aug 2 at 20:22
4
Funny you should ask! NRVO works by constructing the objectstrdirectly intotoLower's return slot. But in this case,toLowerdoes not control wherestrgets constructed (becausestris a parameter). The result is thatstrwill be moved into the return slot â neither copied nor copy-elided, but moved.
â Quuxplusone
Aug 2 at 23:07
add a comment |Â
up vote
12
down vote
accepted
I think interviewer will not be convinced with this solution because here it is no test of logic.
I'm not sure what you mean by "because here it is no test of logic," but if what you mean is "because I found this puzzle too easy," then good! That's what the interviewer is likely to be hiring for: people who solve problems easily and quickly.
When you get an easy problem in an interview, that may be a sign that the interviewer is trying to judge your coding skills rather than your algorithmic/research skills. So make sure your code is as polished as (reasonably) possible.
areAnagramstakes its parameters by non-const reference. This is probably a bug. The interviewer will ask you to "explain your choice." Your answer should be something like "oops, I forgot to remove the&." (This reflects a little badly on your coding skills.)if (res == 1)is a very strange way to test for booleantrue-ness. It would be less unusual, but still a minor yellow flag, to test forif (res == true)orif (res). It would be good to remove the useless variable and test directly forif (areAnagrams(str1, str2)).
Similarly, in the body of areAnagrams, you have written
if (str1.compare(str2) == 0)
return true;
else
return false;
This is a very long-winded and confusing way of writing
return str1 == str2;
and is kind of a big deal. The interviewer is not looking to hire people who write eight lines of convoluted code when one line of simple code would do the job.
You also have an extra blank line at the beginning of areAnagrams; this shows a possible tendency toward sloppiness. The interviewer is not looking to hire people who might "typo" their way into a bug.
On the plus side, your definition of toLower is very good! The interviewer might ask you to explain why you took by value instead of by const&. The interviewer might ask you whether the line return str; makes a copy of the string or whether the copy is elided. (Trick question! The answer is "neither.")
The answer is "neither."Why does NRVO not work in this case?
â yuri
Aug 2 at 20:22
4
Funny you should ask! NRVO works by constructing the objectstrdirectly intotoLower's return slot. But in this case,toLowerdoes not control wherestrgets constructed (becausestris a parameter). The result is thatstrwill be moved into the return slot â neither copied nor copy-elided, but moved.
â Quuxplusone
Aug 2 at 23:07
add a comment |Â
up vote
12
down vote
accepted
up vote
12
down vote
accepted
I think interviewer will not be convinced with this solution because here it is no test of logic.
I'm not sure what you mean by "because here it is no test of logic," but if what you mean is "because I found this puzzle too easy," then good! That's what the interviewer is likely to be hiring for: people who solve problems easily and quickly.
When you get an easy problem in an interview, that may be a sign that the interviewer is trying to judge your coding skills rather than your algorithmic/research skills. So make sure your code is as polished as (reasonably) possible.
areAnagramstakes its parameters by non-const reference. This is probably a bug. The interviewer will ask you to "explain your choice." Your answer should be something like "oops, I forgot to remove the&." (This reflects a little badly on your coding skills.)if (res == 1)is a very strange way to test for booleantrue-ness. It would be less unusual, but still a minor yellow flag, to test forif (res == true)orif (res). It would be good to remove the useless variable and test directly forif (areAnagrams(str1, str2)).
Similarly, in the body of areAnagrams, you have written
if (str1.compare(str2) == 0)
return true;
else
return false;
This is a very long-winded and confusing way of writing
return str1 == str2;
and is kind of a big deal. The interviewer is not looking to hire people who write eight lines of convoluted code when one line of simple code would do the job.
You also have an extra blank line at the beginning of areAnagrams; this shows a possible tendency toward sloppiness. The interviewer is not looking to hire people who might "typo" their way into a bug.
On the plus side, your definition of toLower is very good! The interviewer might ask you to explain why you took by value instead of by const&. The interviewer might ask you whether the line return str; makes a copy of the string or whether the copy is elided. (Trick question! The answer is "neither.")
I think interviewer will not be convinced with this solution because here it is no test of logic.
I'm not sure what you mean by "because here it is no test of logic," but if what you mean is "because I found this puzzle too easy," then good! That's what the interviewer is likely to be hiring for: people who solve problems easily and quickly.
When you get an easy problem in an interview, that may be a sign that the interviewer is trying to judge your coding skills rather than your algorithmic/research skills. So make sure your code is as polished as (reasonably) possible.
areAnagramstakes its parameters by non-const reference. This is probably a bug. The interviewer will ask you to "explain your choice." Your answer should be something like "oops, I forgot to remove the&." (This reflects a little badly on your coding skills.)if (res == 1)is a very strange way to test for booleantrue-ness. It would be less unusual, but still a minor yellow flag, to test forif (res == true)orif (res). It would be good to remove the useless variable and test directly forif (areAnagrams(str1, str2)).
Similarly, in the body of areAnagrams, you have written
if (str1.compare(str2) == 0)
return true;
else
return false;
This is a very long-winded and confusing way of writing
return str1 == str2;
and is kind of a big deal. The interviewer is not looking to hire people who write eight lines of convoluted code when one line of simple code would do the job.
You also have an extra blank line at the beginning of areAnagrams; this shows a possible tendency toward sloppiness. The interviewer is not looking to hire people who might "typo" their way into a bug.
On the plus side, your definition of toLower is very good! The interviewer might ask you to explain why you took by value instead of by const&. The interviewer might ask you whether the line return str; makes a copy of the string or whether the copy is elided. (Trick question! The answer is "neither.")
answered Aug 2 at 17:22
Quuxplusone
9,62011451
9,62011451
The answer is "neither."Why does NRVO not work in this case?
â yuri
Aug 2 at 20:22
4
Funny you should ask! NRVO works by constructing the objectstrdirectly intotoLower's return slot. But in this case,toLowerdoes not control wherestrgets constructed (becausestris a parameter). The result is thatstrwill be moved into the return slot â neither copied nor copy-elided, but moved.
â Quuxplusone
Aug 2 at 23:07
add a comment |Â
The answer is "neither."Why does NRVO not work in this case?
â yuri
Aug 2 at 20:22
4
Funny you should ask! NRVO works by constructing the objectstrdirectly intotoLower's return slot. But in this case,toLowerdoes not control wherestrgets constructed (becausestris a parameter). The result is thatstrwill be moved into the return slot â neither copied nor copy-elided, but moved.
â Quuxplusone
Aug 2 at 23:07
The answer is "neither." Why does NRVO not work in this case?â yuri
Aug 2 at 20:22
The answer is "neither." Why does NRVO not work in this case?â yuri
Aug 2 at 20:22
4
4
Funny you should ask! NRVO works by constructing the object
str directly into toLower's return slot. But in this case, toLower does not control where str gets constructed (because str is a parameter). The result is that str will be moved into the return slot â neither copied nor copy-elided, but moved.â Quuxplusone
Aug 2 at 23:07
Funny you should ask! NRVO works by constructing the object
str directly into toLower's return slot. But in this case, toLower does not control where str gets constructed (because str is a parameter). The result is that str will be moved into the return slot â neither copied nor copy-elided, but moved.â Quuxplusone
Aug 2 at 23:07
add a comment |Â
up vote
9
down vote
I see some things that may help you improve your code.
bool is not int
The bool type is a full-fledged first class type in C++. If I were an interviewer reading this code, I'd be perplexed:
bool res = areAnagrams(str1, str2);
if (res == 1)
std::cout << "Strings are anagramn";
else
std::cout << "Strings are not anagramn";
A similar thing is being done here:
if (str1.compare(str2) == 0)
return true;
else
return false;
First, we are comparing a bool to 1 (an int) which is odd enough. Next, if we're returning the result of the comparison, why don't we return the result of the comparison?
return !str1.compare(str2);
Better still:
return str1 == str2;
Understand references
The prototype of the toLower function is this:
std::string toLower(std::string str);
bool areAnagrams(std::string& str1, std::string& str2);
So reading this, the toLower makes a copy of its argument and areAnagrams uses references. However, the first few lines of the latter function are these:
str1 = toLower(str1);
str2 = toLower(str2);
There's little point to making copies and then assigning the copy back to the original. What I would recommend instead is to have toLower take a reference and areAnagrams pass by value. That way, we have a much more logical interface in which toLower modifies the passed string but areAnagrams does not.
Use auto to simplify code
The better choice for res in main would be to declare it auto instead of explicitly naming bool.
Consider the use of locale
Rather than writing your own toLower, why not use the one in <locale>? Here's how that might look:
auto& facetstd::use_facet<std::ctype<char>>(std::locale());
facet.tolower(&str1.front(), &str1.back());
facet.tolower(&str2.front(), &str2.back());
Use better naming
The function toLower is a good name because (with the suggested change mentioned above) it says what it actually does. However, res is not a good name and it's not necessary to have a separate variable anyway. Instead of this strange construction:
bool res = areAnagrams(str1, str2);
if (res == 1)
std::cout << "Strings are anagramn";
else
std::cout << "Strings are not anagramn";
I would probably instead have written this:
std::cout << "Strings " << (areAnagrams(str1, str2) ? "are" : "are not")
<< " anagramsn";
Although, as @TobySpeight points out in a comment, better for the purposes of translating the string into another language would be to keep the strings intact. One way to do that:
std::cout << (areAnagrams(str1, str2) ? "Strings are anagramsn"
: "Strings are not anagramsn");
Declare variables each on a separate line
Clarify variable declaration by declaring each one on a single line. See Guideline ES.10
Consider namespace or static
During an interview, I'd probably ask why you chose not to encapsulate the functions in a namespace, and why the functions are not static. There are arguments both ways for each of those; be aware of what they are and be able to explain and defend your choices.
std::string::comparereturns <0, 0, or >0, so the first part of your answer doesn't make any sense.
â jamesdlin
Aug 2 at 22:25
@jamesdlin: it was missing a!which is now corrected.
â Edward
Aug 2 at 22:47
3
I meant that the whole "boolis notint" premise is misdirected ("we are comparing aboolto0..."; no, it's comparingintto0). Regarding your edit: I personally dislike!str.compare(str)for the same reason as you originally give:boolis notint, and!on anintseems weird.
â jamesdlin
Aug 2 at 22:55
1
First, withinmainwe haveif (res == 1)which is comparing aboolto anint. Second, I agree that!str1.compare(str2)is not very good, which is why what I recommend instead isreturn str1 == str2;which I suspect we both agree is the most clear and straightforward way to do it.
â Edward
Aug 2 at 23:12
2
Under "Use better naming", you go a bit further than I would. There's an argument against breaking strings into pieces like that - it's an anti-pattern that hinders translation. When your program is likely to be translated (and in an interview you do want to demonstrate that you can work with translators), it's usually better to keep strings whole - this is where C-style format strings can be valuable:std::printf(areAnagrams(str1, str2) ? "%s is an anagram of %sn" : "%s is not an anagram of %sn", str1.c_str(), str2.c_str());
â Toby Speight
Aug 3 at 7:59
 |Â
show 2 more comments
up vote
9
down vote
I see some things that may help you improve your code.
bool is not int
The bool type is a full-fledged first class type in C++. If I were an interviewer reading this code, I'd be perplexed:
bool res = areAnagrams(str1, str2);
if (res == 1)
std::cout << "Strings are anagramn";
else
std::cout << "Strings are not anagramn";
A similar thing is being done here:
if (str1.compare(str2) == 0)
return true;
else
return false;
First, we are comparing a bool to 1 (an int) which is odd enough. Next, if we're returning the result of the comparison, why don't we return the result of the comparison?
return !str1.compare(str2);
Better still:
return str1 == str2;
Understand references
The prototype of the toLower function is this:
std::string toLower(std::string str);
bool areAnagrams(std::string& str1, std::string& str2);
So reading this, the toLower makes a copy of its argument and areAnagrams uses references. However, the first few lines of the latter function are these:
str1 = toLower(str1);
str2 = toLower(str2);
There's little point to making copies and then assigning the copy back to the original. What I would recommend instead is to have toLower take a reference and areAnagrams pass by value. That way, we have a much more logical interface in which toLower modifies the passed string but areAnagrams does not.
Use auto to simplify code
The better choice for res in main would be to declare it auto instead of explicitly naming bool.
Consider the use of locale
Rather than writing your own toLower, why not use the one in <locale>? Here's how that might look:
auto& facetstd::use_facet<std::ctype<char>>(std::locale());
facet.tolower(&str1.front(), &str1.back());
facet.tolower(&str2.front(), &str2.back());
Use better naming
The function toLower is a good name because (with the suggested change mentioned above) it says what it actually does. However, res is not a good name and it's not necessary to have a separate variable anyway. Instead of this strange construction:
bool res = areAnagrams(str1, str2);
if (res == 1)
std::cout << "Strings are anagramn";
else
std::cout << "Strings are not anagramn";
I would probably instead have written this:
std::cout << "Strings " << (areAnagrams(str1, str2) ? "are" : "are not")
<< " anagramsn";
Although, as @TobySpeight points out in a comment, better for the purposes of translating the string into another language would be to keep the strings intact. One way to do that:
std::cout << (areAnagrams(str1, str2) ? "Strings are anagramsn"
: "Strings are not anagramsn");
Declare variables each on a separate line
Clarify variable declaration by declaring each one on a single line. See Guideline ES.10
Consider namespace or static
During an interview, I'd probably ask why you chose not to encapsulate the functions in a namespace, and why the functions are not static. There are arguments both ways for each of those; be aware of what they are and be able to explain and defend your choices.
std::string::comparereturns <0, 0, or >0, so the first part of your answer doesn't make any sense.
â jamesdlin
Aug 2 at 22:25
@jamesdlin: it was missing a!which is now corrected.
â Edward
Aug 2 at 22:47
3
I meant that the whole "boolis notint" premise is misdirected ("we are comparing aboolto0..."; no, it's comparingintto0). Regarding your edit: I personally dislike!str.compare(str)for the same reason as you originally give:boolis notint, and!on anintseems weird.
â jamesdlin
Aug 2 at 22:55
1
First, withinmainwe haveif (res == 1)which is comparing aboolto anint. Second, I agree that!str1.compare(str2)is not very good, which is why what I recommend instead isreturn str1 == str2;which I suspect we both agree is the most clear and straightforward way to do it.
â Edward
Aug 2 at 23:12
2
Under "Use better naming", you go a bit further than I would. There's an argument against breaking strings into pieces like that - it's an anti-pattern that hinders translation. When your program is likely to be translated (and in an interview you do want to demonstrate that you can work with translators), it's usually better to keep strings whole - this is where C-style format strings can be valuable:std::printf(areAnagrams(str1, str2) ? "%s is an anagram of %sn" : "%s is not an anagram of %sn", str1.c_str(), str2.c_str());
â Toby Speight
Aug 3 at 7:59
 |Â
show 2 more comments
up vote
9
down vote
up vote
9
down vote
I see some things that may help you improve your code.
bool is not int
The bool type is a full-fledged first class type in C++. If I were an interviewer reading this code, I'd be perplexed:
bool res = areAnagrams(str1, str2);
if (res == 1)
std::cout << "Strings are anagramn";
else
std::cout << "Strings are not anagramn";
A similar thing is being done here:
if (str1.compare(str2) == 0)
return true;
else
return false;
First, we are comparing a bool to 1 (an int) which is odd enough. Next, if we're returning the result of the comparison, why don't we return the result of the comparison?
return !str1.compare(str2);
Better still:
return str1 == str2;
Understand references
The prototype of the toLower function is this:
std::string toLower(std::string str);
bool areAnagrams(std::string& str1, std::string& str2);
So reading this, the toLower makes a copy of its argument and areAnagrams uses references. However, the first few lines of the latter function are these:
str1 = toLower(str1);
str2 = toLower(str2);
There's little point to making copies and then assigning the copy back to the original. What I would recommend instead is to have toLower take a reference and areAnagrams pass by value. That way, we have a much more logical interface in which toLower modifies the passed string but areAnagrams does not.
Use auto to simplify code
The better choice for res in main would be to declare it auto instead of explicitly naming bool.
Consider the use of locale
Rather than writing your own toLower, why not use the one in <locale>? Here's how that might look:
auto& facetstd::use_facet<std::ctype<char>>(std::locale());
facet.tolower(&str1.front(), &str1.back());
facet.tolower(&str2.front(), &str2.back());
Use better naming
The function toLower is a good name because (with the suggested change mentioned above) it says what it actually does. However, res is not a good name and it's not necessary to have a separate variable anyway. Instead of this strange construction:
bool res = areAnagrams(str1, str2);
if (res == 1)
std::cout << "Strings are anagramn";
else
std::cout << "Strings are not anagramn";
I would probably instead have written this:
std::cout << "Strings " << (areAnagrams(str1, str2) ? "are" : "are not")
<< " anagramsn";
Although, as @TobySpeight points out in a comment, better for the purposes of translating the string into another language would be to keep the strings intact. One way to do that:
std::cout << (areAnagrams(str1, str2) ? "Strings are anagramsn"
: "Strings are not anagramsn");
Declare variables each on a separate line
Clarify variable declaration by declaring each one on a single line. See Guideline ES.10
Consider namespace or static
During an interview, I'd probably ask why you chose not to encapsulate the functions in a namespace, and why the functions are not static. There are arguments both ways for each of those; be aware of what they are and be able to explain and defend your choices.
I see some things that may help you improve your code.
bool is not int
The bool type is a full-fledged first class type in C++. If I were an interviewer reading this code, I'd be perplexed:
bool res = areAnagrams(str1, str2);
if (res == 1)
std::cout << "Strings are anagramn";
else
std::cout << "Strings are not anagramn";
A similar thing is being done here:
if (str1.compare(str2) == 0)
return true;
else
return false;
First, we are comparing a bool to 1 (an int) which is odd enough. Next, if we're returning the result of the comparison, why don't we return the result of the comparison?
return !str1.compare(str2);
Better still:
return str1 == str2;
Understand references
The prototype of the toLower function is this:
std::string toLower(std::string str);
bool areAnagrams(std::string& str1, std::string& str2);
So reading this, the toLower makes a copy of its argument and areAnagrams uses references. However, the first few lines of the latter function are these:
str1 = toLower(str1);
str2 = toLower(str2);
There's little point to making copies and then assigning the copy back to the original. What I would recommend instead is to have toLower take a reference and areAnagrams pass by value. That way, we have a much more logical interface in which toLower modifies the passed string but areAnagrams does not.
Use auto to simplify code
The better choice for res in main would be to declare it auto instead of explicitly naming bool.
Consider the use of locale
Rather than writing your own toLower, why not use the one in <locale>? Here's how that might look:
auto& facetstd::use_facet<std::ctype<char>>(std::locale());
facet.tolower(&str1.front(), &str1.back());
facet.tolower(&str2.front(), &str2.back());
Use better naming
The function toLower is a good name because (with the suggested change mentioned above) it says what it actually does. However, res is not a good name and it's not necessary to have a separate variable anyway. Instead of this strange construction:
bool res = areAnagrams(str1, str2);
if (res == 1)
std::cout << "Strings are anagramn";
else
std::cout << "Strings are not anagramn";
I would probably instead have written this:
std::cout << "Strings " << (areAnagrams(str1, str2) ? "are" : "are not")
<< " anagramsn";
Although, as @TobySpeight points out in a comment, better for the purposes of translating the string into another language would be to keep the strings intact. One way to do that:
std::cout << (areAnagrams(str1, str2) ? "Strings are anagramsn"
: "Strings are not anagramsn");
Declare variables each on a separate line
Clarify variable declaration by declaring each one on a single line. See Guideline ES.10
Consider namespace or static
During an interview, I'd probably ask why you chose not to encapsulate the functions in a namespace, and why the functions are not static. There are arguments both ways for each of those; be aware of what they are and be able to explain and defend your choices.
edited Aug 3 at 11:36
answered Aug 2 at 17:45
Edward
43.8k373199
43.8k373199
std::string::comparereturns <0, 0, or >0, so the first part of your answer doesn't make any sense.
â jamesdlin
Aug 2 at 22:25
@jamesdlin: it was missing a!which is now corrected.
â Edward
Aug 2 at 22:47
3
I meant that the whole "boolis notint" premise is misdirected ("we are comparing aboolto0..."; no, it's comparingintto0). Regarding your edit: I personally dislike!str.compare(str)for the same reason as you originally give:boolis notint, and!on anintseems weird.
â jamesdlin
Aug 2 at 22:55
1
First, withinmainwe haveif (res == 1)which is comparing aboolto anint. Second, I agree that!str1.compare(str2)is not very good, which is why what I recommend instead isreturn str1 == str2;which I suspect we both agree is the most clear and straightforward way to do it.
â Edward
Aug 2 at 23:12
2
Under "Use better naming", you go a bit further than I would. There's an argument against breaking strings into pieces like that - it's an anti-pattern that hinders translation. When your program is likely to be translated (and in an interview you do want to demonstrate that you can work with translators), it's usually better to keep strings whole - this is where C-style format strings can be valuable:std::printf(areAnagrams(str1, str2) ? "%s is an anagram of %sn" : "%s is not an anagram of %sn", str1.c_str(), str2.c_str());
â Toby Speight
Aug 3 at 7:59
 |Â
show 2 more comments
std::string::comparereturns <0, 0, or >0, so the first part of your answer doesn't make any sense.
â jamesdlin
Aug 2 at 22:25
@jamesdlin: it was missing a!which is now corrected.
â Edward
Aug 2 at 22:47
3
I meant that the whole "boolis notint" premise is misdirected ("we are comparing aboolto0..."; no, it's comparingintto0). Regarding your edit: I personally dislike!str.compare(str)for the same reason as you originally give:boolis notint, and!on anintseems weird.
â jamesdlin
Aug 2 at 22:55
1
First, withinmainwe haveif (res == 1)which is comparing aboolto anint. Second, I agree that!str1.compare(str2)is not very good, which is why what I recommend instead isreturn str1 == str2;which I suspect we both agree is the most clear and straightforward way to do it.
â Edward
Aug 2 at 23:12
2
Under "Use better naming", you go a bit further than I would. There's an argument against breaking strings into pieces like that - it's an anti-pattern that hinders translation. When your program is likely to be translated (and in an interview you do want to demonstrate that you can work with translators), it's usually better to keep strings whole - this is where C-style format strings can be valuable:std::printf(areAnagrams(str1, str2) ? "%s is an anagram of %sn" : "%s is not an anagram of %sn", str1.c_str(), str2.c_str());
â Toby Speight
Aug 3 at 7:59
std::string::compare returns <0, 0, or >0, so the first part of your answer doesn't make any sense.â jamesdlin
Aug 2 at 22:25
std::string::compare returns <0, 0, or >0, so the first part of your answer doesn't make any sense.â jamesdlin
Aug 2 at 22:25
@jamesdlin: it was missing a
! which is now corrected.â Edward
Aug 2 at 22:47
@jamesdlin: it was missing a
! which is now corrected.â Edward
Aug 2 at 22:47
3
3
I meant that the whole "
bool is not int" premise is misdirected ("we are comparing a bool to 0..."; no, it's comparing int to 0). Regarding your edit: I personally dislike !str.compare(str) for the same reason as you originally give: bool is not int, and ! on an int seems weird.â jamesdlin
Aug 2 at 22:55
I meant that the whole "
bool is not int" premise is misdirected ("we are comparing a bool to 0..."; no, it's comparing int to 0). Regarding your edit: I personally dislike !str.compare(str) for the same reason as you originally give: bool is not int, and ! on an int seems weird.â jamesdlin
Aug 2 at 22:55
1
1
First, within
main we have if (res == 1) which is comparing a bool to an int. Second, I agree that !str1.compare(str2) is not very good, which is why what I recommend instead is return str1 == str2; which I suspect we both agree is the most clear and straightforward way to do it.â Edward
Aug 2 at 23:12
First, within
main we have if (res == 1) which is comparing a bool to an int. Second, I agree that !str1.compare(str2) is not very good, which is why what I recommend instead is return str1 == str2; which I suspect we both agree is the most clear and straightforward way to do it.â Edward
Aug 2 at 23:12
2
2
Under "Use better naming", you go a bit further than I would. There's an argument against breaking strings into pieces like that - it's an anti-pattern that hinders translation. When your program is likely to be translated (and in an interview you do want to demonstrate that you can work with translators), it's usually better to keep strings whole - this is where C-style format strings can be valuable:
std::printf(areAnagrams(str1, str2) ? "%s is an anagram of %sn" : "%s is not an anagram of %sn", str1.c_str(), str2.c_str());â Toby Speight
Aug 3 at 7:59
Under "Use better naming", you go a bit further than I would. There's an argument against breaking strings into pieces like that - it's an anti-pattern that hinders translation. When your program is likely to be translated (and in an interview you do want to demonstrate that you can work with translators), it's usually better to keep strings whole - this is where C-style format strings can be valuable:
std::printf(areAnagrams(str1, str2) ? "%s is an anagram of %sn" : "%s is not an anagram of %sn", str1.c_str(), str2.c_str());â Toby Speight
Aug 3 at 7:59
 |Â
show 2 more comments
up vote
2
down vote
You know, when deciding whether you have anagrams, you are generally only interested in alpha-numeric characters, the rest are disregarded.
Next, making extraneous copies is generally a bad idea. So, accept a constant view and don't make a copy.
When you accept a mutable reference, be sure that it's obvious from the function-name and arity that it's a mutable reference.
If you can, avoid external linkage. It promotes inlining and avoids unfortunate name-clashes.
Finally, a faster algorithm is normally preferable:
bool isAnagram(std::string_view a, std::string_view b) noexcept
unsigned counts[1ULL + (unsigned char)-1] = ;
for (unsigned char c : a)
++counts[std::tolower(c)];
for (unsigned char c : b)
--counts[std::tolower(c)];
for (std::size_t i = 0; i < std::size(counts); ++i)
if (counts[i] && std::isalnum(i))
return false;
return true;
3
While this may be a faster algorithm, is it a clearer algorithm? I think that for an interview, it may be better to write for clarity.
â Edward
Aug 2 at 18:21
@Edward Yes, I would say so.
â Deduplicator
Aug 2 at 18:49
(2) This code is different from OP's, it ignores non-alnum characters. (3) It's actually slower for short string, as it allocates an array of ~256 ints.
â user176443
Aug 3 at 3:56
Whyint map?unsigned mapwill likely give the right answer in most cases for extremely long strings even if a bucket wraps around, without any signed-overflow UB. (If you can rule out long strings,unsigned char mapcuts the cache footprint by 4 on most modern C++ implementations, and allows faster checking for non-zero buckets on targets where the compiler can use SIMD for the final loop.) I was going to sayuint8_t, but you don't need to stop the code from working on implementations without uint8_t, like some DSPs where char is 32 bits.
â Peter Cordes
Aug 3 at 8:10
1
@user17... If you're checking all characters, then check if lengths are equal as an early-out before doing anything else. But allocating 1kiB on the stack is basically free; literally 1 instruction. Zeroing it has some small cost. Touching it might cause some cache misses, but store-forwarding might manage to hide a lot of the cost of that (i.e. the reloads don't have to wait for the stores to commit); only 32x 32-byte stores, so maybe 32 store-buffer entries for zeroing it. The load part of each increment should forward from the zeroing, but the store part uses another buffer.
â Peter Cordes
Aug 3 at 11:14
 |Â
show 3 more comments
up vote
2
down vote
You know, when deciding whether you have anagrams, you are generally only interested in alpha-numeric characters, the rest are disregarded.
Next, making extraneous copies is generally a bad idea. So, accept a constant view and don't make a copy.
When you accept a mutable reference, be sure that it's obvious from the function-name and arity that it's a mutable reference.
If you can, avoid external linkage. It promotes inlining and avoids unfortunate name-clashes.
Finally, a faster algorithm is normally preferable:
bool isAnagram(std::string_view a, std::string_view b) noexcept
unsigned counts[1ULL + (unsigned char)-1] = ;
for (unsigned char c : a)
++counts[std::tolower(c)];
for (unsigned char c : b)
--counts[std::tolower(c)];
for (std::size_t i = 0; i < std::size(counts); ++i)
if (counts[i] && std::isalnum(i))
return false;
return true;
3
While this may be a faster algorithm, is it a clearer algorithm? I think that for an interview, it may be better to write for clarity.
â Edward
Aug 2 at 18:21
@Edward Yes, I would say so.
â Deduplicator
Aug 2 at 18:49
(2) This code is different from OP's, it ignores non-alnum characters. (3) It's actually slower for short string, as it allocates an array of ~256 ints.
â user176443
Aug 3 at 3:56
Whyint map?unsigned mapwill likely give the right answer in most cases for extremely long strings even if a bucket wraps around, without any signed-overflow UB. (If you can rule out long strings,unsigned char mapcuts the cache footprint by 4 on most modern C++ implementations, and allows faster checking for non-zero buckets on targets where the compiler can use SIMD for the final loop.) I was going to sayuint8_t, but you don't need to stop the code from working on implementations without uint8_t, like some DSPs where char is 32 bits.
â Peter Cordes
Aug 3 at 8:10
1
@user17... If you're checking all characters, then check if lengths are equal as an early-out before doing anything else. But allocating 1kiB on the stack is basically free; literally 1 instruction. Zeroing it has some small cost. Touching it might cause some cache misses, but store-forwarding might manage to hide a lot of the cost of that (i.e. the reloads don't have to wait for the stores to commit); only 32x 32-byte stores, so maybe 32 store-buffer entries for zeroing it. The load part of each increment should forward from the zeroing, but the store part uses another buffer.
â Peter Cordes
Aug 3 at 11:14
 |Â
show 3 more comments
up vote
2
down vote
up vote
2
down vote
You know, when deciding whether you have anagrams, you are generally only interested in alpha-numeric characters, the rest are disregarded.
Next, making extraneous copies is generally a bad idea. So, accept a constant view and don't make a copy.
When you accept a mutable reference, be sure that it's obvious from the function-name and arity that it's a mutable reference.
If you can, avoid external linkage. It promotes inlining and avoids unfortunate name-clashes.
Finally, a faster algorithm is normally preferable:
bool isAnagram(std::string_view a, std::string_view b) noexcept
unsigned counts[1ULL + (unsigned char)-1] = ;
for (unsigned char c : a)
++counts[std::tolower(c)];
for (unsigned char c : b)
--counts[std::tolower(c)];
for (std::size_t i = 0; i < std::size(counts); ++i)
if (counts[i] && std::isalnum(i))
return false;
return true;
You know, when deciding whether you have anagrams, you are generally only interested in alpha-numeric characters, the rest are disregarded.
Next, making extraneous copies is generally a bad idea. So, accept a constant view and don't make a copy.
When you accept a mutable reference, be sure that it's obvious from the function-name and arity that it's a mutable reference.
If you can, avoid external linkage. It promotes inlining and avoids unfortunate name-clashes.
Finally, a faster algorithm is normally preferable:
bool isAnagram(std::string_view a, std::string_view b) noexcept
unsigned counts[1ULL + (unsigned char)-1] = ;
for (unsigned char c : a)
++counts[std::tolower(c)];
for (unsigned char c : b)
--counts[std::tolower(c)];
for (std::size_t i = 0; i < std::size(counts); ++i)
if (counts[i] && std::isalnum(i))
return false;
return true;
edited Aug 3 at 10:50
answered Aug 2 at 17:56
Deduplicator
9,7211744
9,7211744
3
While this may be a faster algorithm, is it a clearer algorithm? I think that for an interview, it may be better to write for clarity.
â Edward
Aug 2 at 18:21
@Edward Yes, I would say so.
â Deduplicator
Aug 2 at 18:49
(2) This code is different from OP's, it ignores non-alnum characters. (3) It's actually slower for short string, as it allocates an array of ~256 ints.
â user176443
Aug 3 at 3:56
Whyint map?unsigned mapwill likely give the right answer in most cases for extremely long strings even if a bucket wraps around, without any signed-overflow UB. (If you can rule out long strings,unsigned char mapcuts the cache footprint by 4 on most modern C++ implementations, and allows faster checking for non-zero buckets on targets where the compiler can use SIMD for the final loop.) I was going to sayuint8_t, but you don't need to stop the code from working on implementations without uint8_t, like some DSPs where char is 32 bits.
â Peter Cordes
Aug 3 at 8:10
1
@user17... If you're checking all characters, then check if lengths are equal as an early-out before doing anything else. But allocating 1kiB on the stack is basically free; literally 1 instruction. Zeroing it has some small cost. Touching it might cause some cache misses, but store-forwarding might manage to hide a lot of the cost of that (i.e. the reloads don't have to wait for the stores to commit); only 32x 32-byte stores, so maybe 32 store-buffer entries for zeroing it. The load part of each increment should forward from the zeroing, but the store part uses another buffer.
â Peter Cordes
Aug 3 at 11:14
 |Â
show 3 more comments
3
While this may be a faster algorithm, is it a clearer algorithm? I think that for an interview, it may be better to write for clarity.
â Edward
Aug 2 at 18:21
@Edward Yes, I would say so.
â Deduplicator
Aug 2 at 18:49
(2) This code is different from OP's, it ignores non-alnum characters. (3) It's actually slower for short string, as it allocates an array of ~256 ints.
â user176443
Aug 3 at 3:56
Whyint map?unsigned mapwill likely give the right answer in most cases for extremely long strings even if a bucket wraps around, without any signed-overflow UB. (If you can rule out long strings,unsigned char mapcuts the cache footprint by 4 on most modern C++ implementations, and allows faster checking for non-zero buckets on targets where the compiler can use SIMD for the final loop.) I was going to sayuint8_t, but you don't need to stop the code from working on implementations without uint8_t, like some DSPs where char is 32 bits.
â Peter Cordes
Aug 3 at 8:10
1
@user17... If you're checking all characters, then check if lengths are equal as an early-out before doing anything else. But allocating 1kiB on the stack is basically free; literally 1 instruction. Zeroing it has some small cost. Touching it might cause some cache misses, but store-forwarding might manage to hide a lot of the cost of that (i.e. the reloads don't have to wait for the stores to commit); only 32x 32-byte stores, so maybe 32 store-buffer entries for zeroing it. The load part of each increment should forward from the zeroing, but the store part uses another buffer.
â Peter Cordes
Aug 3 at 11:14
3
3
While this may be a faster algorithm, is it a clearer algorithm? I think that for an interview, it may be better to write for clarity.
â Edward
Aug 2 at 18:21
While this may be a faster algorithm, is it a clearer algorithm? I think that for an interview, it may be better to write for clarity.
â Edward
Aug 2 at 18:21
@Edward Yes, I would say so.
â Deduplicator
Aug 2 at 18:49
@Edward Yes, I would say so.
â Deduplicator
Aug 2 at 18:49
(2) This code is different from OP's, it ignores non-alnum characters. (3) It's actually slower for short string, as it allocates an array of ~256 ints.
â user176443
Aug 3 at 3:56
(2) This code is different from OP's, it ignores non-alnum characters. (3) It's actually slower for short string, as it allocates an array of ~256 ints.
â user176443
Aug 3 at 3:56
Why
int map? unsigned map will likely give the right answer in most cases for extremely long strings even if a bucket wraps around, without any signed-overflow UB. (If you can rule out long strings, unsigned char map cuts the cache footprint by 4 on most modern C++ implementations, and allows faster checking for non-zero buckets on targets where the compiler can use SIMD for the final loop.) I was going to say uint8_t, but you don't need to stop the code from working on implementations without uint8_t, like some DSPs where char is 32 bits.â Peter Cordes
Aug 3 at 8:10
Why
int map? unsigned map will likely give the right answer in most cases for extremely long strings even if a bucket wraps around, without any signed-overflow UB. (If you can rule out long strings, unsigned char map cuts the cache footprint by 4 on most modern C++ implementations, and allows faster checking for non-zero buckets on targets where the compiler can use SIMD for the final loop.) I was going to say uint8_t, but you don't need to stop the code from working on implementations without uint8_t, like some DSPs where char is 32 bits.â Peter Cordes
Aug 3 at 8:10
1
1
@user17... If you're checking all characters, then check if lengths are equal as an early-out before doing anything else. But allocating 1kiB on the stack is basically free; literally 1 instruction. Zeroing it has some small cost. Touching it might cause some cache misses, but store-forwarding might manage to hide a lot of the cost of that (i.e. the reloads don't have to wait for the stores to commit); only 32x 32-byte stores, so maybe 32 store-buffer entries for zeroing it. The load part of each increment should forward from the zeroing, but the store part uses another buffer.
â Peter Cordes
Aug 3 at 11:14
@user17... If you're checking all characters, then check if lengths are equal as an early-out before doing anything else. But allocating 1kiB on the stack is basically free; literally 1 instruction. Zeroing it has some small cost. Touching it might cause some cache misses, but store-forwarding might manage to hide a lot of the cost of that (i.e. the reloads don't have to wait for the stores to commit); only 32x 32-byte stores, so maybe 32 store-buffer entries for zeroing it. The load part of each increment should forward from the zeroing, but the store part uses another buffer.
â Peter Cordes
Aug 3 at 11:14
 |Â
show 3 more comments
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f200835%2fare-strings-anagram%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password