问题描述
给一非空的单词列表,返回前 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, 2 和 1 次。
注意:
假定 k 总为有效值, 1 ≤ k ≤ 集合元素数。
输入的单词均由小写字母组成。
扩展练习:
尝试以 O(n log k) 时间复杂度和 O(n) 空间复杂度解决。
来源:力扣(LeetCode)
链接:
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题报告
两种解法。
第一种时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
第二种时间复杂度为
O
(
n
l
o
g
k
)
O(nlogk)
O(nlogk) 要注意第二种方法中重载大小判断运算符的方法。
实现代码
// class Solution {
// public:
// static bool cmp(pair<string, int>a, pair<string, int>b){
// if(a.second!=b.second)
// return a.second>b.second;//按照第二个元素从小到大排序
// else return a.first<b.first;
// }
// vector<string> topKFrequent(vector<string>& words, int k) {
// unordered_map<string, int>mp;
// vector<string>ans;
// for(int i=0;i<words.size();i++){
// mp[words[i]]++;
// }
// vector<pair<string, int>>vec;
// for(auto m:mp){
// vec.push_back({m.first, m.second});
// }
// sort(vec.begin(), vec.end(), cmp);
// for(int i=0;i<k;i++){
// ans.push_back(vec[i].first);
// }
// return ans;
// }
// };
typedef pair<int,string> P;//频数,单词
struct Order
{//起到greater的作用,如果a的优先级大于b的,返回true
bool operator()(const P& a,const P& b)const
{//a,b频数大的,优先级大,频数相等,字典序小的优先级大.
return (a.first>b.first||(a.first==b.first&&a.second<b.second));
}
};
class Solution {
public:
vector<string> topKFrequent(vector<string>& words, int k) {
vector<string> ans;
int n=words.size();
Order ord;//比较器
//用于统计词频
unordered_map<string,int> word_freq;
//遍历统计词频
for(string x:words)word_freq[x]++;
//遍历,构造一个大小为k的小顶堆,每次插入元素是O(logk)的,所以建堆是O(nlogk)的
priority_queue<P,vector<P>,Order> pq;
for(auto item:word_freq)
{
P tmp{item.second,item.first};//当前元素
//如果没满继续往里加
if(pq.size()<k)pq.push(tmp);
//否则队列里元素数目一定>=k
else if(ord(tmp,pq.top()))
{//如果tmp的优先级>队首的优先级
pq.push(tmp);
pq.pop();//pop掉队首,也就是优先级小的,应该还剩下k个元素
}
}
//把k个元素逆序输出就好
while(k--)
{
ans.push_back(pq.top().second);
pq.pop();
}
reverse(ans.begin(),ans.end());//O(k)的复杂度
return ans;
}
};
// 作者:ydong17
// 链接:https://leetcode-cn.com/problems/top-k-frequent-words/solution/wei-hu-da-xiao-wei-kde-xiao-ding-dui-ji-ke-onlogk-/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
参考资料
[1] Leetcode 692. 前K个高频单词
[2] 题解区:ydong17