给一非空的单词列表,返回前 k 个出现次数最多的单词。
    返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率,按字母顺序排序。
    示例 1:

    1. 输入: ["i", "love", "leetcode", "i", "love", "coding"], k = 2
    2. 输出: ["i", "love"]
    3. 解析: "i" "love" 为出现次数最多的两个单词,均为2次。
    4. 注意,按字母顺序 "i" "love" 之前。

    示例 2:

    1. 输入: ["the", "day", "is", "sunny", "the", "the", "the", "sunny", "is", "is"], k = 4
    2. 输出: ["the", "is", "sunny", "day"]
    3. 解析: "the", "is", "sunny" "day" 是出现次数最多的四个单词,
    4. 出现次数依次为 4, 3, 2 1 次。

    注意:

    • 假定 k 总为有效值, 1 ≤ k ≤ 集合元素数。
    • 输入的单词均由小写字母组成。

    扩展练习:

    尝试以 O(n log k) 时间复杂度和 O(n) 空间复杂度解决。

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/top-k-frequent-words

    思路:
    哈希表+排序:使用map保存每个单词出现次数,进行排序,取前k个即可。
    优先队列:使用map保存每个单词出现次数,维护一个长度为k的最小堆,长度大于k时,出队堆顶元素即k个单词中频率最低的,就能保证最小堆中是前k个高频单词。出队时是按小到大返回前k个高频单词,所以需要反向。
    复杂度分析:
    哈希表+排序 对长度为n的数组排序,时间复杂度为O(nlogn),空间复杂度O(n)
    优先队列 将n个单词加入优先队列,添加每个单词的复杂度是logk,弹出单词时复杂度是k,k远小于n,所以时间复杂度O(nlogk) ,空间复杂度O(n)
    优先队列-priority queue

    1. //哈希表 + 排序
    2. var topKFrequent = function(words, k) {
    3. const map = new Map();
    4. words.map(word=>{
    5. const cnt = map.get(word) || 0;
    6. map.set(word,cnt+1);
    7. })
    8. const arr = [...map.keys()];
    9. arr.sort((a,b)=>{
    10. if(map.get(a) === map.get(b)){
    11. return a > b ? 1 : -1;//因为 sort是按-1/0/1来处理 直接 a>b 会把boolean结果转成数字 即永远不会出现 -1 这个比较结果
    12. //return a.localeCompare(b); 使用localeCompare函数也可完成比较
    13. }else{
    14. return map.get(b) - map.get(a);
    15. }
    16. })
    17. return arr.slice(0,k);
    18. };
    19. //优先队列
    20. var topKFrequent = function(words, k) {
    21. const map = new Map();
    22. words.map(word => {
    23. const cnt = map.get(word) || 0;
    24. map.set(word, cnt + 1);
    25. });
    26. const pq = new PriorityQueue((a, b) => {
    27. if (map.get(a) === map.get(b)) {
    28. return a > b ;
    29. } else {
    30. return map.get(a) < map.get(b);
    31. }
    32. });
    33. const arr = [...map.keys()];
    34. arr.map((keyword) => {
    35. pq.push(keyword);
    36. if (pq.size() > k) {
    37. pq.pop();
    38. }
    39. });
    40. const result = [];
    41. while (!pq.empty()) {
    42. result.push(pq.pop());
    43. }
    44. //需要注意因将数组反向,因为维护的是最小堆,每次出队的是最小的,所以需要逆序
    45. return result.reverse();
    46. };