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

225 阅读2分钟

记录 1 道算法题

根据字符出现频率排序

leetcode-cn.com/problems/so…


要求: tree --> eetr | eert,按照字符频率升序重组

根据频率排序的问题可以将单词遍历一遍,用一个对象计数,然后按照次数升序或者降序排列,然后遍历一遍生成单词就可以了。

但是这里引进一个新的思路,桶排序。桶排序可以用在知道上限的时候。

首先依然是用一个对象进行计数,但是同时记录最大频率是多少。然后根据这个最大的频率创建这个长度的数组。假如最大频率是7次,就创建长度 7+1 的数组 new Array(7+1),这个所数组称为桶

关键来了,这时候最少1次,最多7次,所有频率都列举了出来,我们只需要将计数对象里面对应次数的字母存到桶的对应下标就可以。假如 tree t:1,r:1,e: 2,这时候桶 new Array(2+1), 桶[1]就是 t 和 r,桶[2]就是 e。

这时候我们就不用进行排序,只要将桶倒序遍历就可以根据频率的降序拼接字母了。而所需要的空间就看最大的频率是多少,所需要的时间因为只要遍历一次,所有看单词有多长和最大的频率是多大。

    function frequencySort(s) {
        s = s.split('')
        const map = {}
        // 单词肯定至少一个字母
        let maxCount = 1
        // 计数
        for (let i = 0; i < s.length; i++) {
          const item = s[i]
          let m = map[item]
          if (m) {
            map[item]++
            maxCount = Math.max(m + 1, maxCount)
          } else {
            map[item] = 1
          }
        }
        // 桶,桶是个二维数组,因为同一个频率可能有多个字母
        const bucket = Array.from(new Array(maxCount + 1), () => new Array())
        s = Object.entries(map)

        for (const [letter, num] of s) {
          // 根据频率存放字母到桶里
          bucket[num].push(letter)
        }

        s = ''
        // 遍历桶
        for (let i = bucket.length - 1; i >= 0; i--) {
          const item = bucket[i]
          // 每个频率存的字母数组
          for (let j = 0; j < item.length; j++) {
            // 根据当前频率重复
            s += item[j].repeat(i)
          }
        }

        return s
   }

结束