题目来源
题目描述
题目解析
根据题意:
- 补全的句子是按照之前出现的频率排列的,高频率的在最上面
- 如果频率相同,就按照字母顺序来显示
规则:
- 每输入一个字符,就返回自动补全的句子
- 如果遇到
#
,表示完整句子结束
分析:
- 因为需要记住频率,那么就肯定需要一个hashmap,建立句子和其出现频率的映射
- 还需要一个字符串 data,用来保存之前输入过的字符
在构造函数 AutocompleteSystem(vector<string> sentences, vector<int> times)
- 参数是:历史输入的句子和句子历史输入的次数
- 因此:需要将其加入hashmap,然后data初始化为空字符串
在 vector<string> input(char c)
函数中:
- 先判断输入字符是否为
#
- 如果是的话,那么就表示当前的data字符串已经是一个完成的句子了,在hashmap中次数加1,并且data清空,返回空集
- 如果不是的话,将当前字符加入data字符串中,然后去找包含data前缀的前三高频句子。
- 关于:找包含data前缀的前三高频句子?遍历 hashmap ,
- 先看前缀是否匹配,如果匹配,那么将这个 pair 加入优先队列中
- 怎么验证当前 data 字符串是否是其前缀呢?没啥好的方法,只能逐个字符比较
- 要找前三高频句子,可以使用优先队列来做,
- 优先队列设计思路是:
- 始终用优先队列保存频率最高的三个句子
- 应该把频率低的后缀字母顺序大的放在队首,以便随时可以移出队列,所以应该是个最小堆,队列元素是
pair<句子,句子的频率>
,并且根据其频率大小进行排序,要重写优先队列的 comparator。
- 如何保持保存频率最高的三个句子?
- 将pair加入优先队列之后,如果发现此时队列中的元素大于三个,那把队首元素移除,因为是最小堆,所以频率小的句子会被先移除
- 优先队列设计思路是:
- 先看前缀是否匹配,如果匹配,那么将这个 pair 加入优先队列中
- 怎么返回结果?优先队列保存着频率最高的三个数字,频率低的在最前面,所以先先出队列的是频率小的句子,所以要加到结果 res 的末尾
class AutocompleteSystem {
public:
AutocompleteSystem(vector<string> sentences, vector<int> times) {
for (int i = 0; i < sentences.size(); ++i) {
freq[sentences[i]] += times[i];
}
data = "";
}
vector<string> input(char c) {
if (c == '#') {
++freq[data];
data = "";
return {};
}
data.push_back(c);
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 f : freq) {
bool matched = true;
for (int i = 0; i < data.size(); ++i) {
if (data[i] != f.first[i]) {
matched = false;
break;
}
}
if (matched) {
q.push(f);
if (q.size() > 3) q.pop();
}
}
vector<string> res(q.size());
for (int i = q.size() - 1; i >= 0; --i) {
res[i] = q.top().first; q.pop();
}
return res;
}
private:
unordered_map<string, int> freq;
string data;
};