Есть слова в массиве, необходимо определить, состоят ли они из одних и тех же букв

Дан массив:

const arr = ['kot', 'tok', 'okt']

Необходимо написать функцию, которая определяет, состоят ли слова в массиве из одинаковых букв

Примеры:

isLetterMatch(["кот", "ток", "окт"]) === true
isLetterMatch(["кабан", "банка"]) === true
isLetterMatch(["кабан","банка","октава"]) === false
isLetterMatch(["кот","мышь","есть"]) === false

Теория: что проверяется и почему так

Что значит «слова из одинаковых букв»

Под «одинаковыми буквами» обычно понимается совпадение не только множества букв, но и количества каждой буквы. Например, «ток» и «кот» подходят, потому что буквы к, о, т встречаются по одному разу в каждом слове.

Важная деталь: если в одном слове буква встречается дважды, а в другом один раз, такие слова не считаются состоящими из одинаковых букв (результат должен быть false).

Идея канонической формы (подписи)

Сравнивать слова посимвольно напрямую неудобно, потому что порядок букв может отличаться. Поэтому вводится «подпись» — преобразование, которое одинаково для всех анаграмм.

В варианте с сортировкой подпись строится так: слово → список символов → сортировка → строка. У анаграмм отсортированные строки совпадают, потому что одинаковые символы после сортировки оказываются в одном и том же порядке.

Нормализация и регистр: зачем это нужно

Приведение к нижнему регистру делает сравнение нечувствительным к регистру: «Кот» и «ток» начинают рассматриваться как одинаковые по буквам.

Нормализация normalize("NFC") помогает в случаях Юникода, когда внешне одинаковые символы могут быть закодированы разными последовательностями кодовых точек. В простых русских словах это встречается реже, но при копировании текста из разных источников (или при наличии диакритики) может проявиться.

normalize() является стандартным методом строк в JavaScript и в современных средах разработки применяется для унификации представления Юникод-символов перед сравнением.

Почему частотная карта иногда лучше сортировки

Сортировка внутри каждого слова обычно требует больше работы, чем простой проход по символам и подсчёт. Частотная карта напрямую хранит смысл задачи: «какая буква сколько раз встречается».

При больших строках частотный подход часто оказывается эффективнее, потому что выполняется один линейный проход по символам, а затем сравнение небольших структур данных.

Схема и таблица

Схема идеи «подписи слова» (вариант с сортировкой):

["кот", "ток", "окт"]
   │
   ├─ "кот" → normalize+lower → ["к","о","т"] → sort → "кот"
   ├─ "ток" → normalize+lower → ["т","о","к"] → sort → "кот"
   └─ "окт" → normalize+lower → ["о","к","т"] → sort → "кот"
                     │
             все подписи равны → true

Таблица выбора подхода:

КритерийСортировка (Вариант A)Частотная карта (Вариант B)
Простота реализацииВысокая (короткий код)Средняя (нужно сравнение Map)
Смысловая ясность «буква → количество»КосвенноПрямо
Оценка сложности на слово длины mПриблизительно O(m log m) из-за сортировкиПриблизительно O(m) на подсчёт + сравнение по ключам
Когда выбиратьУчебные задачи, короткие словаДлинные строки, упор на эффективность

Кратко: для проверки одинаковости букв во всех словах массива достаточно привести каждое слово к одной форме: либо отсортировать его символы и сравнить получившиеся строки, либо построить частотную карту символов и сравнить карты; дополнительные шаги вроде toLowerCase() и normalize("NFC") повышают стабильность сравнения на реальных входных данных.