~/algorithm/

451. 根据字符出现的频率排序

#leetcode#algorithm#js

题目描述

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

示例 1:

输入: "tree"

输出: "eert"

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

示例 2:

输入: "cccaaa"

输出: "cccaaa"

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

示例 3:

输入: "Aabb"

输出: "bbAa"

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

解题思路

将数组转化成 key 是字母,value 是次数的 map,再根据 value 排序,然后依次打印出次数个字母。

解法优化

将if(map[key]) map[key] = 0;优化为map[key] = map[key] || 0;后提高了 15ms 左右。

reduce 和 forEach 之间也有性能上的差别.

第一名的思路是,将 map 按照 key 转换为次数个字母的字符串数组,再按照数组的长度排序,合并数组Object.keys(map).map((key) => key.repeat(map[key])).sort((x, y) => y.length - x.length).join('')

代码展示

/**
 * @param {string} s
 * @return {string}
 */
var frequencySort = function(s) {
  var ac = s.split("").reduce((acc, cur) => {
    acc[cur] = acc[cur] || 0;
    acc[cur]++;
    return acc;
  }, {});

  return Object.entries(ac)
    .sort((a, b) => b[1] - a[1])
    .reduce((acc, cur) => (acc += cur[0].repeat(cur[1])), "");
};

改进后的代码

/**
 * @param {string} s
 * @return {string}
 */
var frequencySort = function(s) {
  let map = {};
  s.split("").forEach(c => {
    map[c] = map[c] || 0;
    map[c]++;
  });

  return Object.keys(map)
    .map(key => key.repeat(map[key]))
    .sort((x, y) => y.length - x.length)
    .join("");
};