Sort Characters of a String by Frequency
Solve this Problems, sort its characters in decreasing order by frequency and return the result — every occurrence of a character stays adjacent, and more frequent characters come first.
Repeatedly scanning for the current most-frequent remaining character works, but redoing that scan for every one of the k distinct characters is quadratic in k. The faster approach counts frequencies once, then sorts the distinct characters by frequency a single time — one clean sort instead of k linear scans.
Test Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
1 ≤ s.length ≤ 5 × 10³ - ◆
s consists of lowercase English letters - ◆
No two distinct letters in s share the same frequency (guarantees one unambiguous answer)
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
| 1 | class Solution { |
| 2 | public String frequencySort(String s) { |
| 3 | Map<Character, Integer> freq = new HashMap<>(); |
| 4 | for (char c : s.toCharArray()) { |
| 5 | freq.put(c, freq.getOrDefault(c, 0) + 1); |
| 6 | } |
| 7 | List<Character> chars = new ArrayList<>(freq.keySet()); |
| 8 | chars.sort((a, b) -> freq.get(b) - freq.get(a)); |
| 9 | StringBuilder result = new StringBuilder(); |
| 10 | for (char c : chars) { |
| 11 | for (int i = 0; i < freq.get(c); i++) { |
| 12 | result.append(c); |
| 13 | } |
| 14 | } |
| 15 | return result.toString(); |
| 16 | } |
| 17 | } |
| 18 |
a1'a' — freq['a'] becomes 1.
Approach & Solutions
Brute Force — Repeatedly Pick the Most Frequent Remaining Character
BruteCount every character's frequency in one pass. Then, for each of the k distinct characters, scan all remaining (not-yet-placed) characters to find whichever currently has the highest frequency, append that many copies of it, and mark it placed. Repeating this "find the max" scan k times is what makes the selection phase quadratic in the number of distinct characters.
O(n + k²)O(n)1class Solution {
2 public String frequencySort(String s) {
3 Map<Character, Integer> freq = new HashMap<>();
4 for (char c : s.toCharArray()) {
5 freq.put(c, freq.getOrDefault(c, 0) + 1);
6 }
7 StringBuilder result = new StringBuilder();
8 Set<Character> used = new HashSet<>();
9 for (int round = 0; round < freq.size(); round++) {
10 char best = ' ';
11 int bestCount = -1;
12 for (char c : freq.keySet()) {
13 if (!used.contains(c) && freq.get(c) > bestCount) {
14 best = c;
15 bestCount = freq.get(c);
16 }
17 }
18 used.add(best);
19 for (int i = 0; i < bestCount; i++) {
20 result.append(best);
21 }
22 }
23 return result.toString();
24 }
25}Optimal — Sort Characters by Frequency
OptimalCount every character's frequency in one pass, same as before. But instead of repeatedly scanning for the current maximum, sort the distinct characters once by frequency, descending, using a real sorting algorithm. Then build the result by walking that sorted order and appending each character its frequency-many times. One sort instead of k linear scans.
O(n + k log k)O(n)1class Solution {
2 public String frequencySort(String s) {
3 Map<Character, Integer> freq = new HashMap<>();
4 for (char c : s.toCharArray()) {
5 freq.put(c, freq.getOrDefault(c, 0) + 1);
6 }
7 List<Character> chars = new ArrayList<>(freq.keySet());
8 chars.sort((a, b) -> freq.get(b) - freq.get(a));
9 StringBuilder result = new StringBuilder();
10 for (char c : chars) {
11 for (int i = 0; i < freq.get(c); i++) {
12 result.append(c);
13 }
14 }
15 return result.toString();
16 }
17}