给定一个字符串,请将字符串里的字符按照出现的频率降序排列。
示例 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) {
let heap = new Heap((a, b) => a.num < b.num)
let map = new Map()
let str = ""
for (let i = 0; i < s.length; i++) {
map.set(s[i], map.has(s[i]) ? map.get(s[i]) + 1 : 1)
}
map.forEach((num, key) => {
heap.push({
num,
key
})
})
while (heap.size()) {
let top = heap.pop()
for (let i = 0; i < top.num; i++) {
str += top.key
}
}
return str
};
堆的一般实现方法
class Heap {
constructor(cmp = "large") {
if (cmp == "large") {
this.cmp = this.large;
} else if (cmp == "small") {
this.cmp = this.small
} else {
this.cmp = cmp
}
this.res = [];
this.cnt = 0;
}
push(val) {
this.cnt++;
this.res.push(val)
this.shiftUp(this.cnt - 1)
}
pop() {
this.cnt--;
const res = this.res[0]
const pop = this.res.pop()
if (this.cnt) {
this.res[0] = pop
this.shiftDown(0)
}
return res
}
shiftUp(i) {
if (i === 0) return
const par = this.getParentIndex(i)
if (this.cmp(this.res[par], this.res[i])) {
this.swap(par, i)
this.shiftUp(par)
}
}
shiftDown(i) {
const l = this.getLeftIndex(i)
const r = this.getRightIndex(i)
if (l < this.cnt && this.cmp(this.res[i], this.res[l])) {
this.swap(i, l)
this.shiftDown(l)
}
if (r < this.cnt && this.cmp(this.res[i], this.res[r])) {
this.swap(i, r)
this.shiftDown(r)
}
}
getParentIndex(i) {
return (i - 1) >> 1
}
getLeftIndex(i) {
return i * 2 + 1
}
getRightIndex(i) {
return i * 2 + 2
}
large = (a, b) => a < b
small = (a, b) => a > b;
swap = (i, j) => [this.res[i], this.res[j]] = [this.res[j], this.res[i]];
top = () => this.res[0];
size = () => this.cnt;
isEmpty = () => this.cnt === 0
}