[路飞]_根据字符出现频率排序

179 阅读2分钟

「这是我参与2022首次更文挑战的第27天,活动详情查看:2022首次更文挑战

leetcode-451 根据字符出现频率排序

题目介绍

给定一个字符串,请将字符串里的字符按照出现的频率降序排列。

示例1

输入:
"tree"

输出:
"eert"

解释:
'e'出现两次,'r''t'都只出现一次。
因此'e'必须出现在'r''t'之前。此外,"eetr"也是一个有效的答案。

示例2

输入:
"cccaaa"

输出:
"cccaaa"

解释:
'c''a'都出现三次。此外,"aaaccc"也是有效的答案。
注意"cacaca"是不正确的,因为相同的字母必须放在一起。

示例3

输入:
"Aabb"

输出:
"bbAa"

解释:
此外,"bbaA"也是一个有效的答案,但"Aabb"是不正确的。
注意'A''a'被认为是两种不同的字符。

解题思路

思路一:根据字符频率直接排序

题目要求按字符串中字符出现的频率降序排列,那么首先就应该遍历整个字符串,然后记录每个字符出现的频率,为了提高效率,这里使用哈希表 Map 来记录每个字母出现的频率,然后按照每个字母出现的频率从高到低进行排序,之后再次遍历排序之后的数组,根据每个字母的频率进行新字符串的拼接,最后返回新的字符串

解题代码

var frequencySort = function(s) {
    const map = new Map()
    for(let i = 0; i < s.length; i++) {
        if(!map.has(s[i])) {
            map.set(s[i], 1)
        } else {
            map.set(s[i], map.get(s[i]) + 1)
        }
    }
    // map.entries() 可以返回 [[key, value], [key, value]...] 
    const arr = [...map.entries()]
    arr.sort((a, b) => b[1] - a[1])
    let ans = ''
    for(let i = 0; i < arr.length; i++) {
        // 每个字符的出现了多少次,就在新字符串中拼接多少个字符
        while(arr[i][1]--) {
            ans += arr[i][0]
        }
    }
    return ans
};

思路二:桶排序

桶排序同样需要先计算每个字符出现的频率,不同于思路一的是,在统计每个字符出现频率的过程中,需要记录频率出现的最大值 max,然后定义一个长度为 max + 1 的数组 bucket(桶),然后将每个字符放置到下标与对应字符出现频率相同的位置上,之后再遍历整个桶,将字符按下标频率拼接到新字符串上即可

解题代码

var frequencySort = function(s) {
    // 还是先利用 Map 存储每个字符出现的频率,同时记录频率的最大值
    const map = new Map()
    let max = 0
    for(let i = 0; i < s.length; i++) {
        if(!map.has(s[i])) {
            map.set(s[i], 1)
        } else {
            map.set(s[i], map.get(s[i]) + 1)
        }
        max = Math.max(max, map.get(s[i]))
    }
    
    // 定义一个大小为 max + 1 的桶,因为大小为 max + 1,数组下标才能到 max
    // 然后将桶中的每个位置都放置一个空数组,因为可能会出现频率相同的字符,需要用数组记录所有频率相同的字符
    const buckets = new Array(max + 1).fill(0).map(() => new Array())
    
    // 将字符放置到频率对应下标的数组中
    for (const [key, value] of map.entries()) {
        buckets[value].push(key)
    }
    let ans = ''
    for (let i = buckets.length - 1; i > 0; i--) {
        const bucket = buckets[i]
        while (bucket.length) {
            const ch = bucket.pop()
            // 按每个字符出现的频率拼接到新字符串上
            for(let j = 0; j < i; j++) {
                ans += ch
            }
        }
    }
    return ans
};