Необходимо проверить, являются ли две строки анаграммами друг друга
Анаграмма — это литературный приём, при котором буквы или звуки определённого слова (или словосочетания) переставляются, в результате чего получается другое слово или словосочетание. Такой метод ещё называют «перебуква».
Напишите функцию, проверяющую, являются ли две переданные в функцию строки анаграммами друг друга (регистр букв не имеет значения). Важны только символы, пробелы или знаки препинания не учитываются:
function isAnagram (str, str2) {
// ...
}
isAnagram('finder', 'Friend'); // true
isAnagram('hello', 'bye'); // false
Теория: как проверяются анаграммы
Анаграммы — это две строки, которые состоят из одних и тех же значимых символов в одинаковых количествах, но, возможно, в разном порядке.
По условию регистр не важен, а пробелы и знаки препинания не учитываются, поэтому перед сравнением требуется привести строки к единому виду и удалить “неважные” символы.
Шаг 1 — нормализация и приведение регистра
В Unicode один и тот же “видимый” символ иногда может быть записан разными последовательностями кодовых точек (например, буква с диакритикой может быть “составной” или “комбинированной”).
Чтобы сравнение было корректным, полезно приводить строки к одной форме нормализации, например normalize("NFC"), чтобы одинаково выглядящие символы имели одинаковое внутреннее представление.
Далее требуется игнорировать регистр:
- Обычно достаточно
toLowerCase(), так как цель — сделать единый регистр без зависимости от локали. toLocaleLowerCase()меняет регистр с учётом правил конкретной локали, из‑за чего в некоторых языках возможны отличия.
toLowerCase(), а не локалезависимые преобразования.Шаг 2 — удаление пробелов и пунктуации
Самая частая ошибка — удалять только пробелы, забывая про табы, переносы строк, дефисы, запятые и другие символы.
По условию важны только символы (с практической точки зрения удобнее считать важными “буквы и цифры”), поэтому остальные знаки (пробелы, пунктуация) должны игнорироваться.
Надёжный подход для разных алфавитов:
- Оставлять только буквы и цифры с помощью регулярного выражения с Unicode-свойствами:
/[\p{L}\p{N}]/gu. - Флаг
uобязателен для корректной работы Unicode-режима. - Флаг
gнужен, чтобы извлекались все совпадения.
\p{...} относится к современным возможностям JavaScript (Unicode property escapes) и работает в актуальных версиях браузеров и Node.js; в устаревших окружениях может потребоваться иной фильтр (например, ограничиться латиницей/кириллицей вручную).Шаг 3 — сравнение: сортировка или частоты
Есть два стандартных пути:
- Сортировка:
- Очистить строки.
- Преобразовать в массив символов, отсортировать и сравнить результат.
- Плюс: простота.
- Минус: сложность
O(n log n)из-за сортировки.
- Частоты (часто считается базовым “алгоритмическим” решением):
- Посчитать, сколько раз встречается каждый символ в первой строке.
- Для второй строки вычитать эти количества.
- Если при вычитании получилось отрицательное значение — анаграммы невозможны.
- После обработки все счётчики должны стать нулевыми.
- Сложность
O(n).
Небольшая схема процесса (универсальная для обоих подходов):
Входные строки
│
├─ normalize("NFC")
├─ toLowerCase()
├─ оставить только буквы/цифры (игнорировать пробелы/пунктуацию)
│
└─ сравнение:
├─ вариант А: сортировка и сравнение строк
└─ вариант Б: частоты символов и проверка нуля
Таблица: выбор подхода
| Подход | Идея | Время | Память | Когда выбирать |
|---|---|---|---|---|
| Сортировка | Отсортировать символы и сравнить | O(n log n) | O(n) | Учебные примеры, небольшие строки |
| Частоты (Map) | Сравнить количества каждого символа | O(n) | O(k) | Длинные строки, важна эффективность |
| Частоты + ранний выход | Вычитать и завершать при ошибке | O(n) (в среднем) | O(k) | Частые “не анаграмма”, нужна скорость |
Примечания:
n— длина строки после очистки.k— число различных символов после очистки.
Кратко: для проверки анаграмм необходимо очистить строки (нормализация Unicode, приведение к нижнему регистру, игнорирование пробелов и пунктуации), после чего сравнить либо отсортированные наборы символов, либо (предпочтительнее) частоты символов через Map, что даёт линейную сложность по длине очищенной строки.