大家好,我是挨打的阿木木,爱好算法的前端摸鱼老。最近会频繁给大家分享我刷算法题过程中的思路和心得。如果你也是想提高逼格的摸鱼老,欢迎关注我,一起学习。
题目
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记录字符串中每个字符出现的次数; - 对字符根据出现次数做一个从大到小的排序;
- 将字符根据出现的次数分别
push进结果数组中; - 将结果数组转成字符串。
实现
/**
* @param {string} s
* @return {string}
*/
var frequencySort = function(s) {
let map = new Map();
let arr = [];
const n = s.length;
for (let i = 0; i < n; i++) {
// 如果出现过,加次数,没出现过的记录
if (map.has(s[i])) {
arr[map.get(s[i])].count++;
} else {
// 建立索引之间的关系
map.set(s[i], arr.length);
arr.push({ key: s[i], count: 1 });
}
}
// 按照出现次数排序
// 然后按出现次数push进结果中,最终转成字符串
return arr.sort((a, b) => b.count - a.count).reduce((total, cur) => {
while (cur.count) {
total += cur.key;
cur.count--;
}
return total;
}, "");
};
桶排序
思路
- 用
map记录字符串中每个字符出现的次数; - 记录下最多的出现次数
maxCount,然后创建出maxCount + 1个桶,每个桶里面是一个数组; - 按出现的次数把它们放进各自的桶中;
- 从后面的桶依次往前取出元素;
- 将数组转成字符串。
这也是比较标准的用空间换时间的一种解决方案。
实现
/**
* @param {string} s
* @return {string}
*/
var frequencySort = function(s) {
let map = new Map();
let maxCount = 0;
// 记录每个元素出现的次数,同时找到最多的次数
const n = s.length;
for (let i = 0; i < n; i++) {
let cur = (map.get(s[i]) || 0) + 1
map.set(s[i], cur);
maxCount = Math.max(maxCount, cur);
}
let buckets = new Array(maxCount + 1).fill(0).map(v => new Array());
// 按出现次数放进桶中
for (let [key, value] of map) {
buckets[value].push(key);
}
let result = "";
// 依次从桶中拿出即可
for (let i = maxCount; i > 0; i--) {
for (let j = 0; j < buckets[i].length; j++) {
for (let k = 1; k <= i; k++) {
result += buckets[i][j];
}
}
}
return result;
};
看懂了的小伙伴可以点个关注、咱们下道题目见。如无意外以后文章都会以这种形式,有好的建议欢迎评论区留言。