计算范围内的字符串

时间:2015-03-28 08:34:34

标签: algorithm data-structures

给定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.

2 个答案:

答案 0 :(得分:0)

  1. 对于给定的字符串,创建一个地图字符串 - >在输入中排序的位置
  2. 对于每个查询,在排序的位置使用2个二进制搜索l和r,以查找范围内出现的次数

答案 1 :(得分:0)

以下是此问题的标准解决方案:

  1. 让我们有三种类型的事件:查询开始,查询结束并出现字符串。它们应按给定数组中它们的位置的升序处理。

  2. 到目前为止,我们还会将字符串中的地图维护到其出现次数。

  3. 当我们遇到开始事件时,我们需要从答案中减去与查询对应的字符串出现次数。

  4. 当我们看到结束事件时,我们需要将此字符串的出现次数添加到答案中。

  5. 当出现字符串时,我们只是将其放入地图中。

  6. 如果使用基于树的地图实现,则时间复杂度为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;
    }