题目描述
题目分析
/**
* @param {string} s
* @return {string}
*/
var frequencySort = function(s) {
};
题目只给了一个参数 s,要求返回的是一个排序之后的字符串
解题思路
本题要根据频率排序,所以我先把频率用一个对象存起来,然后用堆将对象中所有键排序,最后从堆中不断地弹出元素,重新构建一个新的字符串返回
算法,数据结构
堆:按频率存储字符(注意是存储不同的字符,而不是 s 中的所有字符)
对象:存储字符的频率
过程
声明变量
声明对象 freq,堆 h(堆的实现过程此处忽略),堆的主要方法有:
extract:弹出堆顶元素
insert:插入一个元素
isEmpty:检查堆是否为空
统计频率
遍历字符串,统计每个字符频率:
for (const x of s) {
if (freq[x]) {
freq[x]++
} else {
freq[x] = 1
}
}
拿到每个字符的频率
堆排序,插入每个字符
然后,想堆中 insert 字符:
这一步需要特别注意,插入的是 Object.keys(freq),而不是 s 中的所有字符
做完上面的插入之后,堆中所有字符按照频率已经排好,接下来构建字符串
构建字符串
从堆中不断地弹出元素,并从 freq 查找他的频率,最后构建字符串
代码
/**
* @param {string} s
* @return {string}
*/
var frequencySort = function (s) {
const freq = {}
const h = new Heap((a, b) => freq[a] <= freq[b])
for (const x of s) {
if (freq[x]) {
freq[x]++
} else {
freq[x] = 1
}
}
for (const x of Object.keys(freq)) {
h.insert(x)
}
let ret = ""
while (!h.isEmpty()) {
const c = h.extract()
let f = freq[c]
while (f--) {
ret += c
}
}
return ret
}
class Heap {
constructor(compreFn) {
this.compreFn = compreFn
this.heap = []
}
getLeftIndex(index) {
return index * 2 + 1
}
getRightIndex(index) {
return index * 2 + 2
}
getParentIndex(index) {
return Math.floor((index - 1) / 2)
}
size() {
return this.heap.length
}
isEmpty() {
return this.heap.length === 0
}
swap(parent, index) {
const arr = this.heap
;[arr[parent], arr[index]] = [arr[index], arr[parent]]
}
insert(value) {
const index = this.heap.length
this.heap.push(value)
this.siftUp(index)
}
siftUp(index) {
let parent = this.getParentIndex(index)
while (index > 0 && this.compreFn(this.heap[parent], this.heap[index])) {
this.swap(parent, index)
index = parent
parent = this.getParentIndex(index)
}
}
extract() {
if (this.isEmpty()) return
if (this.size() === 1) return this.heap.pop()
const removedItem = this.heap[0]
this.heap[0] = this.heap.pop()
this.siftDown(0)
return removedItem
}
siftDown(index) {
let element = index
const left = this.getLeftIndex(index)
const right = this.getRightIndex(index)
if (
index < this.size() &&
this.compreFn(this.heap[element], this.heap[left])
) {
element = left
}
if (
index < this.size() &&
this.compreFn(this.heap[element], this.heap[right])
) {
element = right
}
if (index !== element) {
this.swap(element, index)
this.siftDown(element)
}
}
top() {
return this.heap[0]
}
}