diff --git a/src/main/java/com/thealgorithms/strings/SortCharacterByFrequency.java b/src/main/java/com/thealgorithms/strings/SortCharacterByFrequency.java new file mode 100644 index 000000000000..f3f5424e8104 --- /dev/null +++ b/src/main/java/com/thealgorithms/strings/SortCharacterByFrequency.java @@ -0,0 +1,66 @@ +// Reference: https://leetcode.com/problems/sort-characters-by-frequency/ +package com.thealgorithms.strings; +import java.util.*; + +// Problem: Sort Characters By Frequency +// Pattern: HashMap + Priority Queue (Heap) +// Difficulty: Medium + +/* + Approach: + 1. Count frequency of each character using a HashMap. + 2. Store characters in a max-heap (PriorityQueue) based on frequency. + 3. If frequencies are same, sort by character (lexicographically). + 4. Extract from heap and append characters 'frequency' times. + + Time Complexity: O(n log n) + Space Complexity: O(n) +*/ + +class SortCharacterByFrequency { + public String frequencySort(String s) { + + // Step 1: Count frequency of each character + Map map = new HashMap<>(); + + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + + // Increment frequency using getOrDefault + map.put(ch, map.getOrDefault(ch, 0) + 1); + } + + // Step 2: Create max-heap based on frequency + PriorityQueue> pq = new PriorityQueue<>((a, b) -> { + // Higher frequency comes first + int diff = b.getValue() - a.getValue(); + + // If frequency same, sort by character + if (diff == 0) return a.getKey() - b.getKey(); + + return diff; + }); + + // Add all entries to heap + pq.addAll(map.entrySet()); + + // Step 3: Build result string + StringBuilder sb = new StringBuilder(); + + while (!pq.isEmpty()) { + + Map.Entry entry = pq.poll(); + + char key = entry.getKey(); // character + int freq = entry.getValue(); // frequency + + // Append character 'freq' times + for (int i = 0; i < freq; i++) { + sb.append(key); + } + } + + // Step 4: Return final string + return sb.toString(); + } +} diff --git a/src/test/java/com/thealgorithms/strings/SortCharacterByFrequencyTest.java b/src/test/java/com/thealgorithms/strings/SortCharacterByFrequencyTest.java new file mode 100644 index 000000000000..f2d033e72010 --- /dev/null +++ b/src/test/java/com/thealgorithms/strings/SortCharacterByFrequencyTest.java @@ -0,0 +1,49 @@ +package com.thealgorithms.strings; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class SortCharacterByFrequencyTest { + + private final SortCharacterByFrequency solution = new SortCharacterByFrequency(); + + @Test + void testBasicCase() { + String result = solution.frequencySort("tree"); + + // Possible outputs: "eert" or "eetr" + assertTrue(result.equals("eert") || result.equals("eetr")); + } + + @Test + void testSingleCharacter() { + assertEquals("a", solution.frequencySort("a")); + } + + @Test + void testEmptyString() { + assertEquals("", solution.frequencySort("")); + } + + @Test + void testAllSameCharacters() { + assertEquals("aaaa", solution.frequencySort("aaaa")); + } + + @Test + void testMixedCharacters() { + String result = solution.frequencySort("cccaaa"); + + // Possible outputs: "cccaaa" or "aaaccc" + assertTrue(result.equals("cccaaa") || result.equals("aaaccc")); + } + + @Test + void testWithNumbersAndLetters() { + String result = solution.frequencySort("Aabb"); + + // 'b' appears twice → should come first + assertTrue(result.startsWith("bb")); + } +}