Как реализовать проверку анаграмм для двух строк
Что проверяют
Умеете ли вы довести простую задачу до рабочего кода и, что для QA важнее, сразу увидеть граничные случаи. Следом почти всегда просят: «А теперь перечислите тесты для этой функции».
Как отвечать
Начните с уточнений: учитывать ли регистр, пробелы и знаки препинания, считать ли «е» и «ё» одной буквой. От ответа зависит нормализация входа.
Дальше решения с оценкой сложности:
- сортировка:
sorted(a) == sorted(b), O(n log n) по времени, коротко и читаемо; - подсчёт символов:
collections.Counter(a) == Counter(b)или словарь, где по первой строке счётчик растёт, по второй убывает. O(n) по времени и O(k) памяти, где k это число разных символов; - массив на 26 ячеек: если алфавит заранее известен и мал, счётчики в списке фиксированной длины вместо словаря.
Перед любым вариантом стоит дешёвая проверка длины: строки разной длины не анаграммы. Нормализацию делайте явно: s.casefold(), удаление пробелов, при необходимости unicodedata.normalize("NFC", s), иначе «é» одним символом и «é» из буквы с комбинирующим акцентом окажутся разными.
Затем набор тестов, это ваша сильная сторона на такой задаче:
- позитивные:
listenиsilent, две одинаковые строки; - повторы букв:
aabиabbдолжны датьFalse; - пустые строки: две пустые обычно считаются анаграммами, об этом стоит договориться;
- регистр и пробелы:
Dormitoryиdirty room; - Юникод: кириллица, эмодзи, составные символы.
Где спотыкаются
Сравнивают множества: set("aab") == set("abb") даёт True, хотя это не анаграммы. Множество теряет количество повторов.
Пишут сортировку и подсчёт в одной функции подряд, как будто второй шаг что-то добавляет. Выберите один способ и объясните, почему именно он.
Не задают уточняющих вопросов о регистре и пробелах, а потом спорят с интервьюером о «правильном» результате для Listen и Silent. Для тестировщика неясное требование это первое, что нужно вскрыть.