Sort Characters By Frequency solution and explanation
9 more videos on this problem
Sort Characters By Frequency | Leetcode #451Techdose · 7:15 · 63K views
451. Sort Characters By Frequency | 3 Ways | Sorting | Hash Table | Bucket SortAryan Mittal · 24:25 · 35K views
Sort Characters By Frequency - Leetcode 451 - PythonNeetCodeIO · 10:57 · 33K views
Sort Characters By Frequency | LeetCode 451 | Top Interview Question | Java DSA | Geekster AmazonGeekster · 11:44 · 13K views
Sort Characters By Frequency | Sort Characters By Frequency LeetCode Java | LeetCode - 451The Code Mate · 7:04 · 3K views
SORT CHARACTERS BY FREQUENCY | LEETCODE 451 | PYTHON BUCKET SORT SOLUTIONCracking FAANG · 14:27 · 876 views
Leetcode 451. Sort Characters By Frequency | JavaScript | Hash TableSantamaria Code · 7:11 · 360 views
HOW TO Sort Characters By Frequency - Leetcode 451Lit Code · 5:32 · 352 views
Sort character by frequency - Google interview question | leetcode #451 python solutionTanay Chauli · 8:53 · 294 views
Sort Characters By Frequency | 451 Leetcode | Python3CodeMeThere · 5:11 · 246 views
The problem
Given a string s, sort it in decreasing order based on the frequency of the characters. The frequency of a character is the number of times it appears in the string.
Return the sorted string. If there are multiple answers, return any of them.
Example 1:
Input: s = "tree" Output: "eert" Explanation: 'e' appears twice while 'r' and 't' both appear once. So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also a valid answer.
Example 2:
Input: s = "cccaaa" Output: "aaaccc" Explanation: Both 'c' and 'a' appear three times, so both "cccaaa" and "aaaccc" are valid answers. Note that "cacaca" is incorrect, as the same characters must be together.
Example 3:
Input: s = "Aabb" Output: "bbAa" Explanation: "bbaA" is also a valid answer, but "Aabb" is incorrect. Note that 'A' and 'a' are treated as two different characters.
Constraints:
1 <= s.length <= 5 * 105sconsists of uppercase and lowercase English letters and digits.
Approach overview
Problem Overview: Given a string s, reorder its characters so that characters with higher frequency appear first. If two characters have the same frequency, their relative order does not matter. The goal is to efficiently count occurrences and rebuild the string sorted by frequency.
Approach 1: HashMap + Sorting (O(n log k) time, O(n) space)
Count the frequency of every character using a HashMap. Once frequencies are known, convert the map entries into a list and sort them by frequency in descending order. After sorting, iterate through the pairs and append each character frequency times to the result string. The sorting step dominates the runtime with O(k log k), where k is the number of unique characters (at most n). This approach is simple and readable, making it a strong default when working with hash tables and sorting.
The key insight is separating the problem into two phases: counting and ordering. Counting is linear using a hash lookup per character, and sorting ensures the highest frequency characters appear first. Many implementations also replace sorting with a priority queue (max heap), which repeatedly extracts the highest-frequency character. That version has the same O(n log k) complexity but uses a heap instead of sorting.
Approach 2: Counting + Bucket Sort (O(n) time, O(n) space)
A faster approach avoids comparison-based sorting entirely. First compute character frequencies with a map or fixed-size array. Then create a bucket array where index i stores all characters that appear exactly i times. Because the maximum frequency is at most n, the bucket array size is n + 1. Iterate the buckets from highest frequency down to 1 and append each character i times to the result.
This works because frequencies are integers within a limited range. Instead of sorting characters by frequency, you directly place them into frequency-indexed buckets. Building the frequency map takes O(n), distributing characters into buckets takes O(k), and constructing the result string takes O(n). The entire process runs in linear time, which makes this the optimal solution for large inputs and a good demonstration of bucket sort principles.
Recommended for interviews: Start with the HashMap + sorting approach because it clearly shows the frequency-count pattern used in many string problems. After that, mention the bucket sort optimization. Interviewers typically expect candidates to recognize that sorting by frequency can be replaced with buckets for an O(n) solution.
Approach 1: Using HashMap and Sorting
This approach involves using a hash map to count the frequency of each character, followed by sorting the characters by frequency in descending order. Here's how the approach works step-by-step:
- Use a hash map (or a dictionary) to store the frequency of each character in the string.
- Convert the hash map to a list of tuples (or a priority queue), where each tuple contains a character and its frequency.
- Sort this list of tuples primarily by frequency in descending order. If two characters have the same frequency, the order can be arbitrary since any valid ordering is acceptable.
- Construct the result string by repeating each character in the sorted list according to its frequency.
def frequencySort(s: str) -> str:
from collections import Counter
freq_map = Counter(s)
sorted_chars = sorted(freq_map.items(), key=lambda x: -x[1])
return ''.join(char * freq for char, freq in sorted_chars)import java.util.*;
class Solution {
public String frequencySort(String s) {
Map<Character, Integer> freqMap = new HashMap<>();
for (char c : s.toCharArray()) {
freqMap.put(c, freqMap.getOrDefault(c, 0) + 1);
}
List<Map.Entry<Character, Integer>> list = new ArrayList<>(freqMap.entrySet());
list.sort((a, b) -> b.getValue() - a.getValue());
StringBuilder result = new StringBuilder();
for (Map.Entry<Character, Integer> entry : list) {
result.append(String.valueOf(entry.getKey()).repeat(entry.getValue()));
}
return result.toString();
}
}#include <string>
#include <unordered_map>
#include <vector>
#include <algorithm>
std::string frequencySort(std::string s) {
std::unordered_map<char, int> freq_map;
for (char c : s) {
++freq_map[c];
}
std::vector<std::pair<int, char>> freq_vector;
for (const auto& pair : freq_map) {
freq_vector.emplace_back(pair.second, pair.first);
}
std::sort(freq_vector.begin(), freq_vector.end(), std::greater<>());
std::string result;
for (const auto& pair : freq_vector) {
result += std::string(pair.first, pair.second);
}
return result;
}function frequencySort(s) {
const freqMap = {};
for (const char of s) {
freqMap[char] = (freqMap[char] || 0) + 1;
}
const sortedChars = Object.entries(freqMap).sort((a, b) => b[1] - a[1]);
return sortedChars.map(([char, freq]) => char.repeat(freq)).join('');
}#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int cmpFunc(const void *a, const void *b) {
return (*(int*)b - *(int*)a);
}
char* frequencySort(char* s) {
int freq[256] = {0};
int len = strlen(s);
for (int i = 0; i < len; i++) {
freq[(int)s[i]]++;
}
int charList[256];
for (int i = 0; i < 256; i++) charList[i] = i;
qsort(charList, 256, sizeof(int), cmpFunc);
char* result = (char*)malloc(len + 1);
int index = 0;
for (int i = 0; i < 256 && index < len; i++) {
char c = (char)charList[i];
while (freq[c]-- > 0) {
result[index++] = c;
}
}
result[len] = '\0';
return result;
}using System;
using System.Collections.Generic;
using System.Linq;
public class Solution {
public string FrequencySort(string s) {
var freqMap = new Dictionary<char, int>();
foreach (char c in s) {
if (!freqMap.ContainsKey(c)) freqMap[c] = 0;
freqMap[c]++;
}
var sortedChars = freqMap.OrderByDescending(pair => pair.Value);
return string.Concat(sortedChars.Select(pair => new string(pair.Key, pair.Value)));
}
}In this Python solution, the collections.Counter class is used to create a frequency map of the characters. We then sort the items of this map based on frequency and concatenate them to form the result string.
Time Complexity: O(n log n), where n is the length of the string due to sorting.
Space Complexity: O(n), for the frequency map storage.
Approach 2: Using Counting Sort and Bucket Sort
This approach leverages the Bucket Sort technique where we'll map frequencies to characters directly. This is especially efficient when the range of possible frequencies is low compared to the number of characters.
- Count the frequency of each character using a fixed-size array (as we are dealing with ASCII).
- Create an array of buckets, where each bucket at index
istores characters appearingitimes. - Build the output from the highest frequency bucket to the lowest.
def frequencySort(s: str) -> str:
from collections import defaultdict
freq_map = defaultdict(int)
for char in s:
freq_map[char] += 1
max_freq = max(freq_map.values())
buckets = [[] for _ in range(max_freq + 1)]
for char, freq in freq_map.items():
buckets[freq].append(char)
result = []
for freq in range(max_freq, 0, -1):
for char in buckets[freq]:
result.append(char * freq)
return ''.join(result)import java.util.*;
class Solution {
public String frequencySort(String s) {
Map<Character, Integer> freqMap = new HashMap<>();
int maxFreq = 0;
for (char c : s.toCharArray()) {
int freq = freqMap.getOrDefault(c, 0) + 1;
freqMap.put(c, freq);
if (freq > maxFreq) maxFreq = freq;
}
List<Character>[] buckets = new List[maxFreq + 1];
for (int i = 0; i <= maxFreq; i++) {
buckets[i] = new ArrayList<>();
}
for (char key : freqMap.keySet()) {
int freq = freqMap.get(key);
buckets[freq].add(key);
}
StringBuilder sb = new StringBuilder();
for (int i = maxFreq; i > 0; i--) {
for (char c : buckets[i]) {
sb.append(String.valueOf(c).repeat(i));
}
}
return sb.toString();
}
}#include <string>
#include <vector>
#include <unordered_map>
std::string frequencySort(std::string s) {
std::unordered_map<char, int> freq_map;
int max_freq = 0;
for (char c : s) {
max_freq = std::max(max_freq, ++freq_map[c]);
}
std::vector<std::vector<char>> buckets(max_freq + 1);
for (const auto& pair : freq_map) {
buckets[pair.second].push_back(pair.first);
}
std::string result;
for (int freq = max_freq; freq > 0; --freq) {
for (char c : buckets[freq]) {
result.append(freq, c);
}
}
return result;
}function frequencySort(s) {
const freqMap = {};
let maxFreq = 0;
for (const char of s) {
freqMap[char] = (freqMap[char] || 0) + 1;
maxFreq = Math.max(maxFreq, freqMap[char]);
}
const buckets = Array.from({ length: maxFreq + 1 }, () => []);
for (const char in freqMap) {
const freq = freqMap[char];
buckets[freq].push(char);
}
let result = '';
for (let i = maxFreq; i > 0; i--) {
for (const char of buckets[i]) {
result += char.repeat(i);
}
}
return result;
}#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* frequencySort(char* s) {
int freq[256] = {0};
int len = strlen(s);
for (int i = 0; i < len; i++) {
freq[(int)s[i]]++;
}
char* result = (char*)malloc(len + 1);
int index = 0;
for (int i = len; i > 0; i--) {
for (int j = 0; j < 256; j++) {
if (freq[j] == i) {
for (int k = 0; k < i; k++) {
result[index++] = (char)j;
}
}
}
}
result[len] = '\0';
return result;
}using System;
using System.Collections.Generic;
using System.Linq;
public class Solution {
public string FrequencySort(string s) {
var freqMap = new Dictionary<char, int>();
int maxFreq = 0;
foreach (var c in s) {
if (!freqMap.ContainsKey(c)) freqMap[c] = 0;
maxFreq = Math.Max(maxFreq, ++freqMap[c]);
}
var buckets = new List<char>[maxFreq + 1];
for (int i = 0; i <= maxFreq; i++) buckets[i] = new List<char>();
foreach (var kvp in freqMap) {
buckets[kvp.Value].Add(kvp.Key);
}
var result = new System.Text.StringBuilder();
for (int i = maxFreq; i > 0; i--) {
foreach (var c in buckets[i]) {
result.Append(c, i);
}
}
return result.ToString();
}
}In this Python solution, we first use a defaultdict to obtain the frequency table. After establishing frequency buckets, we build the result by iterating over frequencies in descending order.
Time Complexity: O(n), since we distribute the frequencies and read back them in linear time.
Space Complexity: O(n), for the result string and bucket storage.
Approach 3: Hash Table + Sorting
We use a hash table cnt to count the occurrences of each character in the string s. Then, we sort the key-value pairs in cnt in descending order by the number of occurrences. Finally, we concatenate the characters according to the sorted order.
The time complexity is O(n + k times log k), and the space complexity is O(n + k), where n is the length of the string s, and k is the number of distinct characters.
function frequencySort(s: string): string {
const cnt: Map<string, number> = new Map();
for (const c of s) {
cnt.set(c, (cnt.get(c) || 0) + 1);
}
const cs = Array.from(cnt.keys()).sort((a, b) => cnt.get(b)! - cnt.get(a)!);
const ans: string[] = [];
for (const c of cs) {
ans.push(c.repeat(cnt.get(c)!));
}
return ans.join('');
}func frequencySort(s string) string {
cnt := map[byte]int{}
for i := range s {
cnt[s[i]]++
}
cs := make([]byte, 0, len(s))
for c := range cnt {
cs = append(cs, c)
}
sort.Slice(cs, func(i, j int) bool { return cnt[cs[i]] > cnt[cs[j]] })
ans := make([]byte, 0, len(s))
for _, c := range cs {
ans = append(ans, bytes.Repeat([]byte{c}, cnt[c])...)
}
return string(ans)
}use std::collections::HashMap;
impl Solution {
pub fn frequency_sort(s: String) -> String {
let mut cnt = HashMap::new();
for c in s.chars() {
cnt.insert(c, cnt.get(&c).unwrap_or(&0) + 1);
}
let mut cs = cnt.into_iter().collect::<Vec<(char, i32)>>();
cs.sort_unstable_by(|(_, a), (_, b)| b.cmp(&a));
cs.into_iter()
.map(|(c, v)| vec![c; v as usize].into_iter().collect::<String>())
.collect()
}
}class Solution {
/**
* @param String $s
* @return String
*/
function frequencySort($s) {
$cnt = array_count_values(str_split($s));
$cs = array_keys($cnt);
usort($cs, function ($a, $b) use ($cnt) {
return $cnt[$b] <=> $cnt[$a];
});
$ans = '';
foreach ($cs as $c) {
$ans .= str_repeat($c, $cnt[$c]);
}
return $ans;
}
}Complexity comparison
| Approach | Complexity |
|---|---|
| Using HashMap and Sorting | Time Complexity: O(n log n), where n is the length of the string due to sorting. |
| Using Counting Sort and Bucket Sort | Time Complexity: O(n), since we distribute the frequencies and read back them in linear time. |
| Hash Table + Sorting | – |
Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| HashMap + Sorting | O(n log k) | O(n) | General solution that is simple to implement and easy to explain in interviews |
| HashMap + Max Heap | O(n log k) | O(n) | Useful when repeatedly extracting highest frequency elements |
| Counting + Bucket Sort | O(n) | O(n) | Best performance when frequencies are bounded and linear-time solution is desired |
Frequently asked questions
Is Sort Characters By Frequency easy or hard?
Sort Characters By Frequency is generally considered a medium-level problem. The core challenge is recognizing the frequency-count pattern and selecting the right structure to order characters efficiently, such as sorting, a heap, or bucket sort.
Sort Characters By Frequency Python/Java solution
In Python or Java, the common solution counts characters with a dictionary or HashMap, then sorts the entries by frequency in descending order and builds the output string. Python often uses collections.Counter with sorted, while Java uses HashMap with a custom comparator or priority queue.
How to solve Sort Characters By Frequency in O(n)?
Use a frequency map to count occurrences of each character. Create an array of buckets where index i stores characters that appear i times. Iterate from the highest frequency bucket down to 1 and append characters accordingly. Since each character is processed a constant number of times, the overall complexity is O(n).
What is the best approach for Sort Characters By Frequency?
The most practical solution uses a HashMap to count character frequencies and then sorts the characters by frequency in descending order. This runs in O(n log k) time where k is the number of unique characters. An even faster approach uses bucket sort to achieve O(n) time by grouping characters by their frequency.
Is Sort Characters By Frequency asked at Google/Amazon/Meta?
Frequency counting and string reordering problems appear frequently in interviews at companies like Amazon, Google, and Meta. Variations often test knowledge of hash tables, heaps, and bucket sort techniques for efficiently ordering elements by frequency.
What data structure is used in Sort Characters By Frequency?
The core data structure is a HashMap (or frequency array) used to count character occurrences. Depending on the solution, the ordering step uses sorting, a max heap (priority queue), or bucket sort to arrange characters by decreasing frequency.
What is the time complexity of Sort Characters By Frequency?
The HashMap plus sorting approach runs in O(n log k) time, where n is the string length and k is the number of distinct characters. Using bucket sort reduces the complexity to O(n) because characters are placed into frequency-indexed buckets instead of being comparison-sorted.
