[路飞]_692. 前K个高频单词

117 阅读2分钟

「这是我参与2022首次更文挑战的第11天,活动详情查看:2022首次更文挑战

692. 前K个高频单词

给一非空的单词列表,返回前 k 个出现次数最多的单词。

返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率,按字母顺序排序。

「示例1:」
输入: ["i", "love", "leetcode", "i", "love", "coding"], k = 2
​
输出: ["i", "love"]
​
解析: "i""love" 为出现次数最多的两个单词,均为2次。
    注意,按字母顺序 "i""love" 之前。
「示例2:」
输入: ["the", "day", "is", "sunny", "the", "the", "the", "sunny", "is", "is"], k = 4
​
输出: ["the", "is", "sunny", "day"]
​
解析: "the", "is", "sunny""day" 是出现次数最多的四个单词,
    出现次数依次为 4, 3, 21 次。
注意:
  • 假定 k 总为有效值, 1 ≤ k ≤ 集合元素数。
  • 输入的单词均由小写字母组成。

解题思路

1. 由题意我们可知,题目是让我们根据单词出现的次数,由大到小返回该单词,如果次数一致则比较他们的字母顺序进行排序
2. 这就属于一个求最值题目,我们就可以用堆的概念来解这个题目
3. 我们先模拟一个堆的push pop 和 堆顶元素的读取
4. 然后我们用hashmap来记录当前单词出现的次数
5. 然后我们在用map的值来维护一个最小堆
6. 最后我们返回结果集合即可

代码实现

/**
 * 692. 前K个高频单词
 * @param {string[]} words
 * @param {number} k
 * @return {string[]}
 */
class MinHeap { // 构建一个最小堆
  constructor(k) {
    this.arr = []; // 默认是空
    this.size = 0; // 初始值大小是0
    this.max = k; // 最大值为k
  }
​
  push(val) {  // 入堆的push操作
    this.arr.push(val);
    this.size++;
    if (this.size > 1) {
      let cur = this.size - 1,
        parent = (cur - 1) >> 1;
      while (cur > 0 && compare(this.arr[cur], this.arr[parent])) {
        [this.arr[cur], this.arr[parent]] = [this.arr[parent], this.arr[cur]];
        cur = parent;
        parent = (cur - 1) >> 1;
      }
    }
    if (this.size > this.max) this.pop();
  }
​
  pop() { // 弹出pop操作
    if (this.size === 1) {
      this.size = 0;
      return this.arr.pop();
    }
    const res = this.arr[0];
    this.arr[0] = this.arr.pop();
    this.size--;
    let cur = 0,
      childl = 1,
      childr = 2;
    while (
      (childl < this.size && compare(this.arr[childl], this.arr[cur])) ||
      (childr < this.size && compare(this.arr[childr], this.arr[cur]))
    ) {
      if (childr < this.size && compare(this.arr[childr], this.arr[childl])) {
        [this.arr[childr], this.arr[cur]] = [this.arr[cur], this.arr[childr]];
        cur = childr;
      } else {
        [this.arr[childl], this.arr[cur]] = [this.arr[cur], this.arr[childl]];
        cur = childl;
      }
      childl = cur * 2 + 1;
      childr = cur * 2 + 2;
    }
    return res;
  }
​
  top() { // 返回堆顶元素
    return this.arr[0];
  }
}
​
function compare(arr1, arr2) { // 比较当前元素出现的次数,如果次数相同就比较他们单词的顺序
  // ['XXX', 1]
  if (arr1[1] === arr2[1]) return arr1[0] > arr2[0];
  return arr1[1] < arr2[1];
}
var topKFrequent = function (words, k) {
  const map = new Map(); // new一个map集合
  for (let item of words) { 
    map.set(item, (map.get(item) || 0) + 1); // 遍历集合,来记录单词出现的次数
  }
  const heap = new MinHeap(k); // 构建堆
  map.forEach((item, times) => {
    let value = [times, item];
    if (heap.size < k || compare(heap.top(), value)) { // 判断当前元素是否可以入堆
      heap.push(value);
    }
  });
  console.log(heap.arr);
  let res = [];
  // [['a', 1], ['b', 2], ['c', 3]]
  while (heap.size) { // 结果集合处理
    res.unshift(heap.pop()[0]);
  }
  return res; // 返回结果
};
​
​

如果你对这道题目还有疑问的话,可以在评论区进行留言;

graph TD
Start --> Stop