思路:由题目可得,字符串中字典最小的子串是单个字符,那么,问题则转化为,在一个字符串中,求字典最小的字符的个数,即区间最值问题,遇到区间问题,我们可以考虑用前缀和。
而题目是要求我们写一个带区间查询功能的算法,且查询次数有一定大小,所以,我们应该让查询的时间复杂度尽量小,这里,我们可以用到前缀和,即先预处理好数据,然后查询的时候直接用
前缀和:
我们先把输入的字符串S进行预处理。
那么在这个问题中,如何预处理,才能让区间查询最值速度更快呢?
想法:
求出 S 中前 n(1,2,3,.....)个字符中每一个字符的个数 k。
即 S[ n ][ char ] = 个数
例如 ABBCACAC
S[1]['A']=1
S[2]['A']=1 S[2]['B']=1
S[3]['A']=1 S[3]['B']=2
S[4]['A']=1 S[4]['B']=2 S[4]['C']=1
.....
那么,求区域 [ L , R ] 中各个字符的个数,就可以用 S[ L ][ char ] - S[ R ][ char ]
再而,S里面的字符字典是按 ascil 排序的,
只要我们用 count = S[ L ][ char ] - S[ R ][ char ] 从A开始记录区间内各个字符的个数(即按字典大小,从小到大记录)
如果 count ≠ 0,当前的 char 就是字典最小的字符,而 count 就是个数。
代码样例:
#include<iostream>
using namespace std;
const int maxn = 1e5 + 1;
char s[maxn]; //字符串
int map[maxn][91]; // 记录前 n 个字符各个字母的数量
int main() {
int T, n, q, i, j, t;
int k, num = 0;
scanf("%d", &T); // 数据组数
while (T--) {
printf("Case #%d:\n", ++num);
scanf("%d", &n); //字母总个数
scanf("%d", &q); //查询次数
//初始化 记录表
for (i = 1; i <= n; i++)
for (j = 65; j <= 90; j++)
map[i][j] = 0;
for (k = 1; k <= n; k++) {
cin >> s[k];
for (int t = 65; t <= 90; t++)
map[k][t] = map[k - 1][t]; // 把第 n-1 行各个字母的个数 更新 到第 n 行
map[k][s[k]] += 1;
}
while (q--) {
scanf("%d", &i); // L
scanf("%d", &j); // R
for (k = 65; k <= 90; k++) {
t = map[j][k] - map[i-1][k]; // 区间各个字母的个数
if (t != 0) {
printf("%d\n", t);
break;
}
}
}
}
return 0;
}
有错误请指出 - -