Как реализовать проверку анаграмм для двух строк
Что проверяют
Базовую алгоритмику и то, задаёте ли вы уточняющие вопросы до кода. Следом почти всегда спрашивают про сложность по времени и памяти и про регистр, пробелы и нелатинские символы.
Как отвечать
Сначала уточните условия: учитывается ли регистр, игнорируются ли пробелы и знаки препинания, какой алфавит. Затем три решения с оценкой:
- сортировка: привести строки к нужному виду, отсортировать символы и сравнить. O(n log n) по времени, коротко и понятно:
a.toCharArray().sorted() == b.toCharArray().sorted(); - массив счётчиков: для строчной латиницы
IntArray(26), по первой строке увеличиваете, по второй уменьшаете, в конце все нули. O(n) по времени и O(1) по памяти, самый быстрый вариант; - хэш-таблица: для произвольного алфавита, включая кириллицу. В Kotlin это
a.groupingBy { it }.eachCount() == b.groupingBy { it }.eachCount(), тоже O(n), но с упаковкой символов и накладными расходамиHashMap.
Проверку длины ставьте первой как быстрый выход, но уже после нормализации: если пробелы игнорируются, сравнивать исходные длины нельзя. Для регистра в Kotlin берите lowercase(): он не зависит от локали устройства, в отличие от toLowerCase() без аргументов из Java, где на турецкой локали I превращается в ı.
Упомяните тесты на JUnit: пустые строки, одинаковые строки, разная длина, пара aab и abb, где набор букв совпадает, а количество нет.
Где спотыкаются
Берут массив на 26 элементов и не проговаривают ограничение. На строке с кириллицей или цифрой получается выход за границы массива.
Забывают про Unicode. Char в Kotlin это единица UTF-16, эмодзи занимают две, а буква «é» может прийти одним символом или двумя (буква плюс комбинируемый знак). Для строгой проверки строки нормализуют через java.text.Normalizer и считают кодовые точки.
Сравнивают только множества символов через toSet(). Тогда aab и abb считаются анаграммами, хотя количество букв разное.