📌  相关文章
📜  字符串范围查询,用于对带有更新的不同字符的数量进行计数

📅  最后修改于: 2021-04-17 08:41:06             🧑  作者: Mango

给定长度为N的字符串S,以及以下类型的Q个查询:

例子:

天真的方法:

查询类型1:将字符串的第i个字符替换为给定字符。
查询类型2:从L到R遍历字符串,并计算不同字符的数量。

时间复杂度: O(N 2 )

高效方法:此方法基于频率计数算法。
这个想法是使用HashMap来映射带有Ordered_set的字符串的不同字符,该字符存储了所有出现的索引。使用Ordered_set是因为它基于Red-Black树,因此字符的插入和删除将采用O(log N)。

  1. 将字符串的所有字符及其索引插入哈希映射
  2. 对于类型1的查询,请在哈希映射中删除索引i处出现的字符并在索引i中插入处出现的字符X。
  3. 对于类型2的查询,遍历所有26个字符并检查其出现范围是否在[L,R]范围内,如果是,则增加计数。遍历后打印计数值。

下面是上述方法的实现:

C++
#include 
using namespace std;
  
#include 
#include 
using namespace __gnu_pbds;
  
#define ordered_set                 \
    tree, \
         rb_tree_tag,               \
         tree_order_statistics_node_update>
  
// Function that returns the lower-
// bound of the element in ordered_set
int lower_bound(ordered_set set1, int x)
{
    // Finding the position of
    // the element
    int pos = set1.order_of_key(x);
  
    // If the element is not
    // present in the set
    if (pos == set1.size()) {
        return -1;
    }
  
    // Finding the element at
    // the position
    else {
        int element = *(set1.find_by_order(pos));
  
        return element;
    }
}
  
// Utility function to add the
// position of all characters
// of string into ordered set
void insert(
    unordered_map& hMap,
    string S, int N)
{
    for (int i = 0; i < N; i++) {
        hMap[S[i] - 'a'].insert(i);
    }
}
  
// Utility function for update
// the character at position P
void Query1(
    string& S,
    unordered_map& hMap,
    int pos, char c)
{
  
    // we delete the position of the
    // previous character as new
    // character is to be replaced
    // at the same position.
    pos--;
    int previous = S[pos] - 'a';
    int current = c - 'a';
    S[pos] = c;
    hMap[previous].erase(pos);
    hMap[current].insert(pos);
}
  
// Utility function to determine
// number of different characters
// in given range.
void Query2(
    unordered_map& hMap,
    int L, int R)
{
    // Iterate over all 26 alphabets
    // and check if it is in given
    // range using lower bound.
    int count = 0;
    L--;
    R--;
    for (int i = 0; i < 26; i++) {
        int temp = lower_bound(hMap[i], L);
        if (temp <= R and temp != -1)
            count++;
    }
    cout << count << endl;
}
  
// Driver code
int main()
{
    string S = "abcdbbd";
    int N = S.size();
  
    unordered_map hMap;
  
    // Insert all characters with its
    // occurrence in the hash map
    insert(hMap, S, N);
  
    // Queries for sample input
    Query2(hMap, 3, 6);
    Query1(S, hMap, 5, 'z');
    Query2(hMap, 1, 1);
    Query1(S, hMap, 4, 'a');
    Query1(S, hMap, 7, 'd');
    Query2(hMap, 1, 7);
  
    return 0;
}


输出:
3
1
5

时间复杂度: O(Q * logN)其中Q是查询数,N是字符串的大小。