49. Сгруппировать анаграммы
Условие задачи:
Дан массив строк. Необходимо сгруппировать слова, являющиеся анаграммами друг друга.
Внутри каждой группы слова должны быть отсортированы лексикографически. Повторяющиеся элементы необходимо сохранить.
Предполагается, что строки состоят из строчных латинских букв a-z.
Код:
Ввод:
["eat", "tea", "tan", "ate", "nat", "batq"]
Вывод:
[
["ate", "eat", "tea"],
["batq"],
["nat", "tan"]
]
Спойлеры к решению
Подсказки
💡 Частоты букв можно хранить в массиве
int[26].💡 На основе массива частот сформируй ключ для
Map.💡 Значением карты будет список слов с одинаковым ключом.
💡 После группировки отсортируй слова внутри каждой группы.
Решение
public static List<List<String>> groupAnagrams(String[] words) {
if (words == null || words.length == 0) {
return List.of();
}
Map<String, List<String>> groups = new HashMap<>();
for (String word : words) {
int[] frequencies = new int[26];
for (int i = 0; i < word.length(); i++) {
frequencies[word.charAt(i) - 'a']++;
}
StringBuilder key = new StringBuilder();
for (int frequency : frequencies) {
key.append(frequency).append('#');
}
groups.computeIfAbsent(
key.toString(),
ignored -> new ArrayList<>()
).add(word);
}
List<List<String>> result =
new ArrayList<>(groups.values());
for (List<String> group : result) {
Collections.sort(group);
}
result.sort(
Comparator.comparing(group -> group.get(0))
);
return result;
}
Map<String, List<String>> подходит для группировки:
ключ описывает количество каждой буквы в слове;
значение содержит все слова с таким набором букв;
повторяющиеся слова сохраняются в списке.
List<List<String>> естественно представляет итоговый список групп.
Построение групп выполняется за O(S), где S — суммарное количество символов во всех строках. Дополнительно требуется время на обязательную лексикографическую сортировку слов внутри групп.
Дополнительная память — O(S) для хранения результата и ключей групп.