Я делаю некоторые практические вопросы из книги "Cracking the coding interview" и хотел, чтобы некоторые люди просмотрели мой код для ошибок и оптимизаций. Любая обратная связь будет принята с благодарностью.
Вопрос: Напишите метод, чтобы решить, являются ли две строки анаграммами или нет.
/*
Time complexity: O(n^2)
Space complexity: O(n)
*/
bool IsAnagram(std::string str1, std::string str2)
{
if(str1.length() != str2.length())
return false;
for(int i = 0; i < str1.length();i++)
{
bool found = false;
int j = 0;
while(!found && j < str2.length())
{
if(str1[i] == str2[j])
{
found = true;
str2[j] = NULL;
}
j++;
}
if(!found)
return false;
}
return true;
}
Это более эффективно
#include <iostream>
#include <string>
#include <algorithm>
bool IsAnagram(std::string& str1, std::string& str2)
{
if(str1.length() != str2.length())
return false;
std::sort(str1.begin(), str1.end());
std::sort(str2.begin(), str2.end());
return str1.compare(str2) == 0;
}
int main(int argc, char* argv[])
{
std::string an1("army");
std::string an2("mary");
if(IsAnagram(an1, an2))
std::cout << "Hooray!\n";
return 0;
}
Для тех, кто не любит мутирующие строки, возможно, это лучший вариант. Можно либо удалить ссылку на параметры 1 и 2, либо сделать копию внутри функции, как здесь. Таким образом, параметры могут быть const.
bool IsAnagram2(const std::string& str1, const std::string& str2)
{
if(str1.length() != str2.length())
return false;
std::string cpy1(str1), cpy2(str2);
std::sort(cpy1.begin(), cpy1.end());
std::sort(cpy2.begin(), cpy2.end());
return cpy1.compare(cpy2) == 0;
}
O(n)
. Вместо сортировки (это O(n lg n)
), подсчитайте появления символов в s1 и сравните его с символьными вхождениями в s2.
#include <string>
#include <iostream>
#include <limits>
bool IsAnagram(const std::string& s1, const std::string& s2)
{
if (s1.size() != s2.size()) {
return false;
}
int count[std::numeric_limits<char>::max() + (std::size_t)1] = {};
for (auto c : s1) {
count[c]++;
}
for (auto c : s2) {
if (!count[c]) {
return false;
}
count[c]--;
}
return true;
}
int main(int argc, char **argv)
{
std::cout << IsAnagram(argv[1], argv[2]) << std::endl;
return 0;
}
..::max() + (std::size_t)1
? (С другой стороны, я предполагаю, что все эти ответы предполагают ASCII в любом случае - анаграммы Unicode, закодированные в байтовые строки, гораздо менее забавны.) И это может быть хорошей идеей выделить его из стека, если есть платформа с широкий char
и маленький стек.
+1
. Благодарю. Я понимаю, что распределение стека может быть проблемой на некоторых платформах, но я все же предпочитаю его для стандартного алгоритма или алгоритма по умолчанию.
Существует уже стандартный алгоритм std::is_permutation
который позволяет выполнять задачу просто
#include <iostream>
#include <iomanip>
#include <string>
#include <algorithm>
int main()
{
std::string s( "aab" );
std::string t( "aba" );
std::cout << std::boolalpha
<< ( s.size() == t.size() &&
std::is_permutation( s.begin(), s.end(), t.begin() ) )
<< std::endl;
return 0;
}
Выход
true
Таким образом, все потребности ypu - это увидеть, как реализуется алгоритм. :)
Если вам нужна отдельная функция, она будет выглядеть
bool IsAnagram( const std::string &s1, const std::string &s2 )
{
return s1.size() == s2.size() &&
std::is_permutation( s1.begin(), s1.end(), s2.begin() );
}
Использовать std::sort
не подходит, потому что исходные строки будут изменены или вам нужно передать их функции по значению.
O(n lg n)
раз, если вы сортируете обе строки ...