给定N个字符串编号为1到N.我们需要回答Q查询。
每个查询的格式为 l r S
对于每个查询,我们需要打印字符串S出现在[l,r]范围内的次数。
示例:
设N = 3,字符串为:
abc
def
abc
假设我们有3个查询:
查询1:1 2 abc
然后回答是1
查询2:1 3 abc
然后回答是2
查询3:1 2 hgj
然后回答为0
如果N和Q都可以达到100000,那么如何以有效的方式回答查询。此外,输入中每个字符串的大小大于或等于5且小于或等于10.
答案 0 :(得分:0)
答案 1 :(得分:0)
以下是此问题的标准解决方案:
让我们有三种类型的事件:查询开始,查询结束并出现字符串。它们应按给定数组中它们的位置的升序处理。
到目前为止,我们还会将字符串中的地图维护到其出现次数。
当我们遇到开始事件时,我们需要从答案中减去与查询对应的字符串出现次数。
当我们看到结束事件时,我们需要将此字符串的出现次数添加到答案中。
当出现字符串时,我们只是将其放入地图中。
如果使用基于树的地图实现,则时间复杂度为O((N + Q) log N)
;如果使用哈希表,则时间复杂度为O(N + Q)
。
以下是此解决方案的C ++实现:
struct Query {
int left;
int right;
std::string str;
Query(int left, int right, const std::string& str):
left(left), right(right), str(str) {}
};
// Returns the answers to the given queries. Queries' ranges
// must be 1-based.
std::vector<int> answerQueries(const std::vector<std::string>& s,
const std::vector<Query>& queries) {
std::vector<std::vector<int>> startAt(s.size());
std::vector<std::vector<int>> endAt(s.size());
for (size_t i = 0; i < queries.size(); i++) {
Query q = queries[i];
startAt[q.left - 1].push_back(i);
endAt[q.right - 1].push_back(i);
}
std::map<std::string, int> count;
std::vector<int> res(queries.size());
for (size_t i = 0; i < s.size(); i++) {
for (size_t q : startAt[i]) {
res[q] -= count[queries[q].str];
}
count[s[i]]++;
for (size_t q : endAt[i]) {
res[q] += count[queries[q].str];
}
}
return res;
}