问题
给定一个单词列表 words
和一个整数 k
,返回前 k
个出现次数最多的单词。
返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序 排序。
示例 1:
输入: words = ["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 次。
解析
核心是采用map的计数功能。同时采用sort算法,进行排序。
代码
class Solution {
public:
struct Com
{
bool operator()(pair<string, int> kv1, pair<string, int> kv2) //返回bool
{
return kv1.second > kv2.second || (kv1.second == kv2.second && kv1.first < kv2.first);
}
};
vector<string> topKFrequent(vector<string>& words, int k) {
map<string, int> CountMap;
for (auto& str : words) //统计数据
{
CountMap[str]++; //第一次,插入,计数++变成1
}
//CountMap内部已经是字典序排序
//根据V去排序 //只要容器 B 支持从迭代器范围进行初始化,并且容器 A 和容器 B 存储的元素类型相同,你就可以使用容器 A 的迭代器来构造容器 B。
vector<pair<string, int>> SortV(CountMap.begin(), CountMap.end());
//sort不稳定,重写一个稳定的排序
sort(SortV.begin(), SortV.end(), Com()); //需要的是一个对象作为参数,而不是别的
vector<string> vec;
for (size_t i = 0; i < k; ++i)
{
vec.push_back(SortV[i].first);
}
return vec;
}
};
注意点:
1. 只要容器 B 支持从迭代器范围进行初始化,并且容器 A 和容器 B 存储的元素类型相同,你就可以使用容器 A 的迭代器来构造容器 B。
2.Com()是一个匿名对象,由于重载了operator(),所以这个匿名对象可以进行operator()接口的调用
匿名对象的operator接口的形参,采用的是*iterator之后的结果
sort函数支持传入仿函数对象进行重新规整排序方式
3. return kv1.second > kv2.second || (kv1.second == kv2.second && kv1.first < kv2.first); 可以按照second的降序与字典序返回
4.
for (auto& str : words) //统计数据
{
CountMap[str]++; //第一次,插入,计数++变成1
}
第一次指向插入,然后++变成1 后续只进行++
5.为什么转化到vector之后才进行sort排序呢?这是因为sort的迭代器只支持随机迭代器
6.
解析
这段代码是一个 C++ 类 Solution
的定义,其中包含了一个方法 topKFrequent
,该方法用于找出一个字符串数组中出现频率最高的前 k 个单词。以下是代码的详细解读:
类成员
Com
结构体:这是一个自定义的比较类(仿函数),用于定义pair<string, int>
类型的比较逻辑。它重载了operator()
,使得可以比较两个键值对(key-value pairs)。比较逻辑如下:- 首先比较两个键值对的第二个元素(即值),如果第一个键值对的值大于第二个键值对的值,则返回
true
。 - 如果两个键值对的值相等,则比较它们的第一个元素(即键),按照字典序比较字符串,如果第一个键值对的键小于第二个键值对的键,则返回
true
。
- 首先比较两个键值对的第二个元素(即值),如果第一个键值对的值大于第二个键值对的值,则返回
topKFrequent
方法
- 输入参数:一个
vector<string>
类型的words
和一个整数k
。 - 返回类型:一个
vector<string>
,包含出现频率最高的前 k 个单词。
方法步骤:
-
统计频率:
- 使用
map<string, int>
类型的CountMap
来统计每个单词出现的次数。 - 遍历输入的
words
向量,对于每个单词str
,将其在CountMap
中的计数增加 1。
- 使用
-
创建排序向量:
- 使用
CountMap
的迭代器范围来初始化一个vector<pair<string, int>>
类型的SortV
向量。由于map
内部是按键(即字符串)排序的,因此SortV
初始化时已经按照键的字典序排好序。
- 使用
-
排序:
- 使用
std::sort
函数对SortV
进行排序。由于std::sort
默认是不稳定的排序算法,但在这里我们通过提供一个自定义的比较类Com()
,可以确保排序时如果两个元素的频率相同,它们会保持原有的字典序顺序。 Com()
创建了一个Com
类型的匿名对象,并作为比较函数传递给std::sort
。
- 使用
-
提取结果:
- 创建一个
vector<string>
类型的vec
向量,用于存储结果。 - 遍历排序后的
SortV
向量,将前 k 个元素的键(即单词)添加到vec
中。
- 创建一个
-
返回结果:
- 返回
vec
,它包含了出现频率最高的前 k 个单词。
- 返回
注意事项:
std::sort
在 C++ 标准库中实际上是稳定的,所以这里提到的“重写一个稳定的排序”是不必要的。std::sort
保证相同元素之间的相对顺序不会改变。- 代码中注释提到的“容器 A 和容器 B 存储的元素类型相同”是指
map
和vector
中的元素类型都是pair<string, int>
。