最大堆,最小堆,这个算是掌握不了了,一题,看一天,也理解不了哎,就这,这个题解还是我找了比较好理解的,理解不了的还是堆的实现,之前的下沉上浮还能听懂,代码实现蒙蔽了,还的去联系那个最基本的
/*
* @lc app=leetcode.cn id=692 lang=javascript
*
*
*/
// @lc code=start
/**
* @param {string[]} words
* @param {number} k
* @return {string[]}
*/
var topKFrequent = function (words, k) {
let map = new Map();
let heap = [];
// 1 生成一个map先统计words每个单词出现的频次
words.forEach(item => {
map.has(item) ? map.set(item, map.get(item) + 1) : map.set(item, 1)
})
// 2 循环map 先把前k个数放到 堆里面
let i = 0;
map.forEach((value, key) => {
// 循环里面 前k-1个数一次push到堆中 到k-1这个数的时候开始构建堆
if (i < k) {
heap.push([key, value]) // key代表次数 value代表字母
i === k - 1 && buildHeap(map, heap, k)
// k-1以后的数根堆顶的数比较 比小堆顶堆顶(就是小顶堆最小的数) 大于等于堆顶的数就替换
} else if (value > map.get(heap[0][0]) || (value === map.get(heap[0][0]) && key < heap[0][0])) {
heap[0] = [key, value];
heapify(map, heap, k, 0);
}
i++;
})
// 3 heap 排序先比较次数, 相同次数比较字母顺序
let res = heap.sort((a, b) => {
// a[1]代表次数 a[0]代表字母
if (a[1] > b[1]) {
return -1;
} else if (a[1] < b[1]) {
return 1;
} else {
// 这里是次数相同
if (a[0] < b[0]) {
return -1;
} else {
return 1;
}
}
})
// 循环整理出需要返回的数组 res
return res.map(item => item[0]);
};
var buildHeap = function (map, arr, len) {
for (let i = Math.floor(len / 2); i >= 0; i--) {
heapify(map, arr, len, i);
}
}
var heapify = function (map, arr, len, i) {
let l = 2 * i + 1, r = 2 * i + 2, minIndex = i
// 下面这一行不能生命 声明就报错 替换老师报错
// let lNode = map.get(arr[l][0]), rNode = map.get(arr[r][0]), mNode = map.get(arr[minIndex][0]);
// // 次数小或者相等情况排序靠前的置于小堆
if (l < len && (map.get(arr[l][0]) < map.get(arr[minIndex][0]) || (map.get(arr[l][0]) === map.get(arr[minIndex][0]) && arr[l][0] > arr[minIndex][0]))) { // 次数小或者相等情况排序靠前的置于小堆顶
minIndex = l
}
if (r < len && (map.get(arr[r][0]) < map.get(arr[minIndex][0]) || (map.get(arr[r][0]) === map.get(arr[minIndex][0]) && arr[r][0] > arr[minIndex][0]))) {
minIndex = r
}
if (minIndex !== i) {
[arr[minIndex], arr[i]] = [arr[i], arr[minIndex]];
heapify(map, arr, len, minIndex)
}
}
// @lc code=end