Given a non-empty list of words, return the k most frequent elements.

Your answer should be sorted by frequency from highest to lowest. If two words have the same frequency, then the word with the lower alphabetical order comes first.

Example 1:

Input: ["i", "love", "leetcode", "i", "love", "coding"], k = 2
Output: ["i", "love"]
Explanation: "i" and "love" are the two most frequent words.
Note that "i" comes before "love" due to a lower alphabetical order.

Example 2:

Input: ["the", "day", "is", "sunny", "the", "the", "the", "sunny", "is", "is"], k = 4
Output: ["the", "is", "sunny", "day"]
Explanation: "the", "is", "sunny" and "day" are the four most frequent words,
with the number of occurrence being 4, 3, 2 and 1 respectively.

Note:

  1. You may assume k is always valid, 1 ≤ k ≤ number of unique elements.
  2. Input words contain only lowercase letters.

Follow up:

  1. Try to solve it in O(n log k) time and O(n) extra space.
  2. Can you solve it in O(n) time with only O(k) extra space?

这道题让我们求前K个高频词,跟之前那道题 Top K Frequent Elements 极其类似,换了个数据类型就又是一道新题。唯一的不同就是之前那道题对于出现频率相同的数字,没有顺序要求。而这道题对于出现频率相同的单词,需要按照字母顺序来排。但是解法都一样,还是用最小堆和桶排序的方法。首先来看最小堆的方法,思路是先建立每个单词和其出现次数之间的映射,然后把单词和频率的pair放进最小堆,如果没有相同频率的单词排序要求,我们完全可以让频率当作pair的第一项,这样priority_queue默认是以pair的第一项为key进行从大到小的排序,而当第一项相等时,又会以第二项由大到小进行排序,这样第一项的排序方式就与题目要求的相同频率的单词要按字母顺序排列不相符,当然我们可以在存入结果res时对相同频率的词进行重新排序处理,也可以对priority_queue的排序机制进行自定义,这里我们采用第二种方法,我们自定义排序机制,我们让a.second > b.second,让小频率的词在第一位,然后当a.second == b.second时,我们让a.first < b.first,这是让字母顺序大的排在前面(这里博主需要强调一点的是,priority_queue的排序机制的写法和vector的sort的排序机制的写法正好顺序相反,同样的写法,用在sort里面就是频率小的在前面,不信的话可以自己试一下)。定义好最小堆后,我们首先统计单词的出现频率,然后组成pair排序最小堆之中,我们只保存k个pair,超过了就把队首的pair移除队列,最后我们把单词放入结果res中即可,参见代码如下:

解法一:

class Solution {
public:
vector<string> topKFrequent(vector<string>& words, int k) {
vector<string> res(k);
unordered_map<string, int> freq;
auto cmp = [](pair<string, int>& a, pair<string, int>& b) {
return a.second > b.second || (a.second == b.second && a.first < b.first);
};
priority_queue<pair<string, int>, vector<pair<string, int>>, decltype(cmp) > q(cmp);
for (auto word : words) ++freq[word];
for (auto f : freq) {
q.push(f);
if (q.size() > k) q.pop();
}
for (int i = res.size() - ; i >= ; --i) {
res[i] = q.top().first; q.pop();
}
return res;
}
};

下面这种解法还是一种堆排序的思路,这里我们用map,来建立次数和出现该次数所有单词的集合set之间的映射,这里也利用了set能自动排序的特性,当然我们还是需要首先建立每个单词和其出现次数的映射,然后将其组成pair放入map种,map是从小到大排序的,这样我们从最后面取pair,就是次数最大的,每次取出一层中所有的单词,如果此时的k大于该层的单词个数,就将整层的单词加入结果res中,否则就取前K个就行了,取完要更更新K值,如果K小于等于0了,就break掉,返回结果res即可,参见代码如下:

解法二:

class Solution {
public:
vector<string> topKFrequent(vector<string>& words, int k) {
vector<string> res;
unordered_map<string, int> freq;
map<int, set<string>> m;
for (string word : words) ++freq[word];
for (auto a : freq) {
m[a.second].insert(a.first);
}
for (auto it = m.rbegin(); it != m.rend(); ++it) {
if (k <= ) break;
auto t = it->second;
vector<string> v(t.begin(), t.end());
if (k >= t.size()) {
res.insert(res.end(), v.begin(), v.end());
} else {
res.insert(res.end(), v.begin(), v.begin() + k);
}
k -= t.size();
}
return res;
}
};

下面这种解法是一种桶排序的思路,我们根据出现次数建立多个bucket,桶的个数不会超过单词的个数,在每个桶中,我们对单词按字符顺序进行排序。我们可以用个数组来表示桶,每一层中放一个集合,利用set的自动排序的功能,使其能按字母顺序排列。我们还是需要首先建立每个单词和其出现次数的映射,然后将其组成pair放入map种,map是从小到大排序的,这样我们倒序遍历所有的桶,这样取pair,就是次数最大的,每次取出一层中所有的单词,如果此时的k大于该层的单词个数,就将整层的单词加入结果res中,否则就取前K个就行了,取完要更更新K值,如果K小于等于0了,就break掉,返回结果res即可,参见代码如下:

解法三:

class Solution {
public:
vector<string> topKFrequent(vector<string>& words, int k) {
vector<string> res;
unordered_map<string, int> freq;
vector<set<string>> v(words.size() + , set<string>());
for (string word : words) ++freq[word];
for (auto a : freq) {
v[a.second].insert(a.first);
}
for (int i = v.size() - ; i >= ; --i) {
if (k <= ) break;
vector<string> t(v[i].begin(), v[i].end());
if (k >= t.size()) {
res.insert(res.end(), t.begin(), t.end());
} else {
res.insert(res.end(), t.begin(), t.begin() + k);
}
k -= t.size();
}
return res;
}
};

类似题目:

Top K Frequent Elements

Design Search Autocomplete System

参考资料:

https://discuss.leetcode.com/topic/106861/o-nlog-k-priority-queue-c-code

https://discuss.leetcode.com/topic/106868/clean-heap-based-solution-o-nlogk-time-and-o-n-space-16ms

[LeetCode] Top K Frequent Words 前K个高频词的更多相关文章

  1. Top K Frequent Elements 前K个高频元素

    Top K Frequent Elements 347. Top K Frequent Elements [LeetCode] Top K Frequent Elements 前K个高频元素

  2. [LeetCode] Top K Frequent Elements 前K个高频元素

    Given a non-empty array of integers, return the k most frequent elements. For example,Given [1,1,1,2 ...

  3. [LeetCode] 347. Top K Frequent Elements 前K个高频元素

    Given a non-empty array of integers, return the k most frequent elements. Example 1: Input: nums = [ ...

  4. 347 Top K Frequent Elements 前K个高频元素

    给定一个非空的整数数组,返回其中出现频率前 k 高的元素.例如,给定数组 [1,1,1,2,2,3] , 和 k = 2,返回 [1,2].注意:    你可以假设给定的 k 总是合理的,1 ≤ k ...

  5. leetcode的Hot100系列--347. 前 K 个高频元素--hash表+直接选择排序

    这个看着应该是使用堆排序,但我图了一个简单,所以就简单hash表加选择排序来做了. 使用结构体: typedef struct node { struct node *pNext; int value ...

  6. 第k大数(前k大数)

    题目:设计一组N个数,确定其中第k个最大值 1,普通方法(先排序,然后遍历,得到第k大的数)      注:如果是数组,直接arr[k],我们可以对这个乱序数组按照从大到小先行排序,然后取出前k大,总 ...

  7. 快速排序/快速查找(第k个, 前k个问题)

    //快速排序:Partition分割函数,三数中值分割 bool g_bInvalidInput = false; int median3(int* data, int start, int end) ...

  8. 347. Top K Frequent Elements (sort map)

    Given a non-empty array of integers, return the k most frequent elements. Example 1: Input: nums = [ ...

  9. 快速排序算法的实现 && 随机生成区间里的数 && O(n)找第k小 && O(nlogk)找前k大

    思路:固定一个数,把这个数放到合法的位置,然后左边的数都是比它小,右边的数都是比它大 固定权值选的是第一个数,或者一个随机数 因为固定的是左端点,所以一开始需要在右端点开始,找一个小于权值的数,从左端 ...

随机推荐

  1. java操作数据库的通用的类

    package cn.dao; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; ...

  2. iOS之SQLite使用详解

    #pragma mark - 1.引入<sqlite3.h>头文件//添加libsqlite3.0.tbd#import <sqlite3.h>static sqlite3 * ...

  3. 如何使用maven搭建web项目

    博客园注册了有二十多天了,还没有写过博客,今天就发一篇,也便于后面查找笔记. 我个人已经做了几年的java web开发了,由于所在的公司是业务型公司,用的都是一些老旧的稳定技术,很少接触到稍微新点的内 ...

  4. strcat函数

    原型:char  *strcat  ( char  *dest, const  char  *src) 用法:#include  <string.h> 功能:连接两个字符串:strcat( ...

  5. NOIP知识点

    基础算法 贪心 枚举 分治 二分 倍增 高精度 模拟 图论 图 最短路(dijkstra.spfa.floyd) 最小生成树(kruskal.prim) 并查集 拓扑排序 二分图染色 Tarjan 树 ...

  6. 每日冲刺报告--Day2

    敏捷冲刺每日报告--Day2 情况简介 今天我们三个人在一起开了会,分析了我们面临的情况以及下一阶段的计划.一个重大的改进是,我们准备把之前用txt文件格式存储订阅列表改成了文件json格式. 任务进 ...

  7. 2017-2018-1 1623 bug终结者 冲刺003

    bug终结者 冲刺003 by 王旌含 今日任务:优化界面布局,提供图片素材 需求 app图标.主界面图.主界面中按钮图:选择关卡图.关卡按键图:游戏中的小人.箱子.地板.墙.目的地:方向按钮:重置按 ...

  8. C程序第一次作业

    1-1 计算两数的和与差 1 设计思路 (1)主要描述题目算法 第一步:利用指针psum接收sum的地址,指针pdiff接收diff的地址,因此 * psum为sum, * pdiff为diff. 第 ...

  9. Python处理图片缩略图

    CPU 密集型任务和 IO 密集型任务分别选择多进程multiprocessing.Pool.map 和多线程库multiprocessing.dummy.Pool.map import os imp ...

  10. Django 模型层

    基本操作 1.meta类属性汇总 属性名 用法 举例代码 abstract 如果设置abstract=True则这个模式是一个抽象基类   db_table 定义model在数据库中的表名称,如果不定 ...