Лучший способ сгруппировать анаграммы - сопоставить строки с каким-либо представлением гистограммы.
FUNCTION histogram
[input] -> [output]
"dog" -> (1xd, 1xg, 1xo)
"god" -> (1xd, 1xg, 1xo)
"foo" -> (1xf, 2xo)
По сути, при линейном сканировании строки вы можете получить гистограмму, показывающую, сколько каждой буквы она содержит. Небольшой конечный алфавит делает это еще проще (например, с A-Z
, у вас просто есть массив из 26 чисел, по одному на каждую букву).
Теперь анаграммы - это просто слова с одинаковой гистограммой.
Тогда вы можете иметь структуру данных с несколькими картами, которая отображает гистограмму в список слов, имеющих эту гистограмму.
MULTIMAP
[key] => [set of values]
(1xd, 1xg, 1xo) => { "dog", "god" }
(1xf, 2xo) => { "foo" }
Трюк с канонической формой
Вместо работы с гистограммами, вы также можете работать с "канонической формой" строк. По сути, вы определяете для каждой строки ее каноническую форму и два слова являются анаграммами, если они имеют одинаковую каноническую форму.
Одна удобная каноническая форма состоит в том, чтобы буквы в строке располагались в отсортированном порядке.
FUNCTION canonize
[input] -> [output]
"dog" -> "dgo"
"god" -> "dgo"
"abracadabra" -> "aaaaabbcdrr"
Обратите внимание, что это всего лишь один шаг после гистограммного подхода: вы по существу делаете подсчет сортировки для сортировки букв.
Это наиболее практичное решение на вашем языке программирования для вашей проблемы.
Сложность
Создание гистограммы / канонической формы слова практически O(1)
(конечный размер алфавита, конечная максимальная длина слова).
При хорошей реализации хеша get
и put
на мультикарте равны O(1)
.
Вы можете даже иметь несколько мультикарт, по одному на каждую длину слова.
Если есть N
слов, следовательно, помещение всех слов в мультикарты будет O(N)
; затем вывод каждой группы анаграмм просто выводит значения в мультикартах. Это тоже можно сделать в O(N)
.
Это, безусловно, лучше, чем проверять, являются ли каждая пара слов анаграммами (алгоритм O(N^2)
).