[LeetCode] 451. Sort Characters By Frequency

Given a string s, sort it in decreasing order based on the frequency of characters, and return the sorted string.

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 "aaaccc" is also a valid answer.
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 * 105
s consists of English letters and digits.

根据字符出现频率排序。

给定一个字符串 s ,根据字符出现的 频率 对其进行 降序排序 。一个字符出现的 频率 是它出现在字符串中的次数。
返回 已排序的字符串 。如果有多个答案,返回其中任何一个。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/sort-characters-by-frequency
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

题意是给定一个字符串,请将字符串里的字符按照出现的频率降序排列。注意此题的第三个例子,要求区分大小写。最优解是用到类似桶排序 bucket sort 的思路,也可以用 priority queue 做但是复杂度高。

桶排序

桶排序的思路用一个 hashmap 记录input里面所有出现过的字符和他们的频率,然后对hashmap(key, value)按照value大小对key重新排序。最后再按照各个字母出现的次数,拼接好最后的字符串。

桶排序复杂度

时间O(n) - no need to sort anything
空间O(n)

桶排序代码

Java实现

class Solution {
    public String frequencySort(String s) {
        HashMap<Character, Integer> map = new HashMap<>();
        for (char c : s.toCharArray()) {
            map.put(c, map.getOrDefault(c, 0) + 1);
        }

        List<Character>[] bucket = new List[s.length() + 1];
        for (char key : map.keySet()) {
            int freq = map.get(key);
            if (bucket[freq] == null) {
                bucket[freq] = new ArrayList<>();
            }
            bucket[freq].add(key);
        }

        StringBuilder sb = new StringBuilder();
        for (int i = bucket.length - 1; i >= 0; i--) {
            if (bucket[i] != null) {
                for (char c : bucket[i]) {
                    for (int j = 0; j < map.get(c); j++) {
                        sb.append(c);
                    }
                }
            }
        }
        return sb.toString();
    }
}

优先队列

一开始还是用 hashmap 统计每个不同字母的出现次数,并把整个 map.entry 放入一个以 priority queue 构建的最大堆。堆顶元素是出现次数最多的字母。将每个字母写回 StringBuilder 的时候,我们还是按照出现次数从多到少往回写。

复杂度

时间O(nlogk)
空间O(n) - priority queue

优先队列代码

Java实现

class Solution {
    public String frequencySort(String s) {
        HashMap<Character, Integer> map = new HashMap<>();
        for (char c : s.toCharArray()) {
            map.put(c, map.getOrDefault(c, 0) + 1);
        }

        PriorityQueue<Map.Entry<Character, Integer>> queue = new PriorityQueue<>((a, b) -> b.getValue() - a.getValue());
        queue.addAll(map.entrySet());

        StringBuilder sb = new StringBuilder();
        while (!queue.isEmpty()) {
            Map.Entry e = queue.poll();
            for (int i = 0; i < (int) e.getValue(); i++) {
                sb.append(e.getKey());
            }
        }
        return sb.toString();
    }
}
posted @ 2020-01-23 13:07  CNoodle  阅读(211)  评论(0编辑  收藏  举报