TGViewer
crush it easy crush it easy @crushiteasy · 561 subscribers
Post #17 804
Задача "Sort Characters By Frequency"

Уровень: medium

Сегодня решала задачку с использованием не самой частой структуры данных - PriorityQueue. Думаю, стоит зафиксировать решение.

На вход получаем строку состоящую из английских букв (могут быть строчные и заглавные) и символов. Нужно вернуть строку эту же строку, но в отсортированном по убыванию порядке, исходя из того, сколько раз тот или иной символ в ней встречается. Если какие-то символы встречаются одинаковое кол-во раз, то вернуть их в любом порядке (оба ответа ок).

Например, на вход пришла строка: "a55dgggGPP"
Количество повторений символов в строке:
a - 1
5 - 2
g - 3
G - 1
P - 2
Ответ: "gggPP55aG" (варианты "ggg55PPaG", "ggg55PPGa", "gggPP55Ga" тоже ок)

Ограничения:
- Длина строки от 1 до 5 х 10^5
- Строка может состоять только из строчных и заглавных букв английского алфавита и символов

Ссылочка на задачу, как всегда.

Алгоритм решения будет следующий:
1. Подсчитаем и сохраним частоту каждого символа в хэш-таблице
2. Закинем все символы в PriorityQueue, используя собственный Comparator (будем сравнивать частоты символов из хэш-таблицы и закидывать по убыванию - наверху кучи самый частый)
3. Извлекаем из кучи символы и записываем в результирущую строку (использую StringBuilder) в том количестве, в котором они хранятся в нашей хэш-таблице
4. Возвращаем результат

Кстати, есть еще решение, когда храним в куче и символы и частоты, так будет меньше get-ов (можно, поэксперементировать🙌)

Итак, код:
public String frequencySort(String s) {
StringBuilder result = new StringBuilder();
Map<Character, Integer> frequencyMap = new HashMap<>();

for (char c : s.toCharArray()) {
frequencyMap.put(c, frequencyMap.getOrDefault(c, 0) + 1);
}

PriorityQueue<Character> heap = new PriorityQueue<>(
(a, b) -> frequencyMap.get(b) - frequencyMap.get(a));

heap.addAll(frequencyMap.keySet());

while (!heap.isEmpty()) {
char sym = heap.poll();
int count = frequencyMap.get(sym);
for (int i = 0; i < count; i++) {
result.append(sym);
}
}
return result.toString();
}


Временная сложность: O(n log k), т.к. O(n) - добавление в хэш-таблицу (от количества символов в строке), O(k log k) - добавление в очередь, где k - кол-во уникальных символов в строке, извлечение из очереди и добавление в StringBuilder - O(f log k), где f - частота символа, а log k - скорость извлечения. Итого O (n log k) - т.к. повторяем операцию извлечения и присоединения для всех символов в строке. Но в худшем случае скорость будет O (n log n), если k = n, т.е. все символы уникальные.

Пространственная сложность: O(n), т.к. O(k) - хэш-таблица, O(k) - куча (очередь), O (n) - результирующая строка.

Кстати, здесь есть еще подход с решением с использованием массива символов, он чуть выиграет по памяти, но проиграет по скорости на больших строках с большим кол-вом повторений символов:) - хотя leetcode покажет более быстрый runtime.
  • 🔥 9
  • 👍 3
  • ❤ 2
More from @crushiteasy
  1. Nov 12, 2024Задача Remove Element Уровень: easy Итак, задачка следующая: дан массив чисел nums и некот…
  2. Oct 30, 2024Post #28
  3. Oct 30, 2024Нас тут почти 500 человек собралось, круто! Поэтому хочу узнать, кто ты, мой читатель, что…
  4. Oct 9, 2024А теперь еще анонс! - Boosty Сделала себе бусти - https://boosty.to/crushiteasy Написала т…
  5. Oct 9, 2024Принцип SOLID Написала большую статью на Хабр про SOLID с примерами из жизни и разработки.…
  6. Oct 1, 2024Принцип KISS - Keep it simple, Stupid! Немного из истории - принцип пошел из сферы самолет…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →