记录 1 道算法题
前 k 个高频单词
这道题不可避免的要遍历两遍。第一遍统计每个单词出现的次数,第二遍进行排序。
- 统计次数
我们使用一个对象key的唯一性的特点,进行计数。
const map = {}
for(let item of words) {
if (map[item]) {
map[item]++
} else {
map[item] = 1
}
}
排序的时候如果次数相同就要比较字母的顺序,所以我们需要同时准备单词和次数。但是我们只有一个对象,所以我们要通过 Object.entries ,转化成键值对。
- 排序
现在我们已经转成了键值对,接下来就是排序。排序有两种方法,一种是直接排序,另一种就是堆。
- 直接排序
// 利用sort函数进行排序
// 进行字母的排序则需要 String.prototype.localeCompare
// 定制一个给 sort 用的函数, 这时 words 的 item 是键值对
const compare = (a, b) => {
if (a[1] === b[1]) {
const t = a[0].localeCompare(b[0])
// 如果大于0 证明 a 在 b 后面
// 如果小于0 证明 a 在 b 前面
if (t > 0) {
return -1
} else {
return -1
}
} else {
return a[1] - b[1]
}
}
// 因为是升序排列的,所以要截取后面的,并且要反转过来输出。
// 这就是结果, 语言支持的 sort,性能还是不错的。
return words.sort(compare).slice(k * -1).reduceRight((a,b) => {
a.push(b[0]
return a
}, [])
完整代码如下;
function topKFrequent(words, k) {
const map = {}
for(let item of words) {
if (map[item]) {
map[item]++
} else {
map[item] = 1
}
}
words = Object.entries(map)
const compare = (a, b) => {
if (a[1] === b[1]) {
const t = a[0].localeCompare(b[0])
if (t > 0) {
return -1
} else if (t < 0) {
return 1
} else {
return 1
}
} else {
return a[1] - b[1]
}
}
return words.sort(compare).slice(k*-1).reduceRight((a,b) => {
a.push(b[0])
return a
}, [])
}
- 堆(优先队列)
堆的实现在另一篇文章中有介绍,这里直接使用。
完整代码如下:
function topKFrequent(words, k) {
const map = {}
for (let item of words) {
if (map[item]) {
map[item]++
} else {
map[item] = 1
}
}
words = Object.entries(map)
const compare = (a, b) => {
if (a[1] === b[1]) {
const t = a[0].localeCompare(b[0])
if (t > 0) {
return -1
} else if (t < 0) {
return 1
} else {
return 1
}
} else {
return a[1] - b[1]
}
}
/* -------------------------- */
// 这里开始和直接排序不同。
const heap = new Heap(compare)
for (let item of words) {
// 先和堆顶的元素进行判断,不符合直接跳过
if (heap.size() === k && compare(heap.data[0], item) > 0) {
continue
}
heap.push(item)
if (heap.size() > k) {
heap.pop()
}
}
// 因为堆里面是没有排序的,所以要进行一次排序
return heap.data.sort(compare).reduceRight((a, b) => {
a.push(b[0])
return a
}, [])
}
class Heap {
constructor(compare) {
this.data = []
this.compare = compare
}
size() {
return this.data.length
}
swap(n1, n2) {
const { data } = this
const temp = data[n1]
data[n1] = data[n2]
data[n2] = temp
}
push(val) {
this.data.push(val)
this.bubblingUp(this.size() - 1)
}
pop() {
if (this.size() === 0) return null
const { data } = this
const discard = data[0]
const newMember = data.pop()
if (this.size() > 0) {
data[0] = newMember
this.bubblingDown(0)
}
return discard
}
bubblingUp(index) {
while (index > 0) {
const parent = (index - 1) >> 1
const { data } = this
if (this.compare(data[index], data[parent]) < 0) {
this.swap(parent, index)
index = parent
} else {
break
}
}
}
bubblingDown(index) {
const { data } = this
const last = this.size() - 1
while (true) {
const left = index * 2 + 1
const right = index * 2 + 2
let parent = index
if (left <= last && this.compare(data[left], data[parent]) < 0) {
parent = left
}
if (right <= last && this.compare(data[right], data[parent]) < 0) {
parent = right
}
if (index !== parent) {
this.swap(index, parent)
index = parent
} else {
break
}
}
}
}
结束