题目描述
难度分:1300
输入n(1≤n≤2×105)和长为n的字符串s,只包含小写英文字母。
然后输入m(1≤m≤5×104)和m个询问,每个询问输入一个长度≤2×105字符串t,只包含小写英文字母。
保证所有t的长度之和≤2×105。
对于每个询问,输出s的最短前缀长度,这个前缀包含一个子序列p,允许交换p中的字母,使得p=t。保证答案一定存在。
输入样例
9
arrayhead
5
arya
harry
ray
r
areahydra
输出样例
5
6
5
2
9
算法
统计
构建一个映射mp“字母→该字母在s中出现的索引列表”,然后遍历每个名字ti,统计其字母频数记录在counter中。遍历26个字母,只要counter[c]>0,就维护mp[c][counter[i]−1]的最大值,即要凑满counter[i]个字母a
+i要到达的最右索引,这个最大值就是答案。
复杂度分析
时间复杂度
遍历s串构建映射mp,时间复杂度为O(n)。之后遍历ti,对每个名字,O(mi+Σ)就能求得答案(其中Σ=26为字符集大小,mi为ti的长度)。
综上,算法整体的时间复杂度为O(n+m+Σmi=1|ti|),Σmi=1|ti|是O(n)级别。
空间复杂度
mp映射存了s串O(n)级别个位置,之后遍历ti,只需要开固定O(Σ)的空间统计每个ti的字母频数就好。因此,整个算法的额外空间复杂度为O(n+Σ)。
C++ 代码
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
string s;
cin >> n;
cin >> s;
unordered_map<char, vector<int>> mp;
for(int i = 0; i < n; i++) {
mp[s[i]].push_back(i);
}
int m;
cin >> m;
string t;
vector<int> counter(26);
while(m--) {
cin >> t;
for(int i = 0; i < 26; i++) counter[i] = 0;
for(char c: t) counter[c - 'a']++;
int ans = 0;
for(int i = 0; i < 26; i++) {
auto& pos = mp['a' + i];
if(counter[i] > 0) {
ans = max(ans, pos[counter[i] - 1]);
}
}
cout << ans + 1 << '\n';
}
return 0;
}