NC23053 月月查华华的手机
题目
题目描述
月月和华华一起去吃饭了。期间华华有事出去了一会儿,没有带手机。月月出于人类最单纯的好奇心,打开了华华的手机。哇,她看到了一片的QQ推荐好友,似乎华华还没有浏览过。月月顿时醋意大发,出于对好朋友的关心,为了避免华华浪费太多时间和其他网友聊天,她要删掉一些推荐好友。但是为了不让华华发现,产生猜疑,破坏了他们的友情,月月决定只删华华有可能搭讪的推荐好友。
月月熟知华华搭讪的规则。华华想与某个小姐姐搭讪,当且仅当小姐姐的昵称是他的昵称的子序列。为了方便,华华和小姐姐的昵称只由小写字母构成。为了更加方便,保证小姐姐的昵称长度不会比华华的长。
现在月月要快速的判断出哪些推荐好友要删掉,因为华华快回来了,时间紧迫,月月有点手忙脚乱,所以你赶紧写个程序帮帮她吧!
输入描述
第一行输入一个字符串 \(A\) 表示华华的昵称。
第二行输入一个正整数 \(N\) 表示华华的推荐好友的个数。
接下来 \(N\) 行,每行输入一个字符串 \(B_i\) 表示某个推荐好友的昵称。
输出描述
输出 \(N\) 行,对于第 \(i\) 个推荐好友,如果华华可能向她搭讪,输出 Yes
,否则输出 No
。
注意大写,同时也要注意输出效率对算法效率的影响。
示例1
输入
noiauwfaurainairtqltqlmomomo
8
rain
air
tql
ntt
xiaobai
oiiiooo
orzcnzcnznb
ooooo
输出
Yes
Yes
Yes
Yes
No
Yes
No
No
备注
\(1\le|A|\le10^6\) ,\(1\le N\le10^6\),\(1\le\sum_{i=1}^NB_i\le10^6\)
题解
知识点:枚举,字符串。
如果对每个待匹配字符串 \(B_i\) 都用普通双指针搜索一遍完整的字符串 \(A\) ,那么时间复杂度将会是 \(O(\lvert A \rvert N)\) ,显然是不行的。(但不知道为什么这里能过而且还比正解快QWQ)。
因为每次都是对同一个字符串匹配,可以考虑整合字符串中有用的信息优化双指针的遍历。我们希望每次在字符串 \(A\) 的指针能更快的到达下一个需要并且存在的字母,即需要预处理某字母当前位置往后第一个位置。因此,考虑用数组 \(nxt[i][j]\) 表示第 \(i\) 位往后第一次出现字母 \((j+'a')\) 的位置。
因为需要知道最近一次的出现的位置,正着预处理肯定不好因为无法确定某个位置下一个某字母出现在哪里,而可以倒着预处理可以解决这个问题,因为后面的都已经遍历过了(大部分处理下一个位置枚举都是逆着来的),考虑用数组 \(last[i]\) 表示目前字母 \((i+'a')\) 最近的位置。注意在一个位置 \(i\) 要先将 \(last[0 \cdots 25 ]\) 赋给 \(nxt[i][0 \cdots 25]\) ,再处理 \(last\) ,不存在就赋值为 \(-1\)。
最后,遍历 \(B_i\) 注意一些小细节即可。
时间复杂度 \(O(\lvert A \rvert + N)\)
空间复杂度 \(O(\lvert A \rvert)\)
代码
#include <bits/stdc++.h>
using namespace std;
int last[26+7];
int nxt[1000007][26+7];
int main(){
string str;
cin>>str;
memset(last,-1,sizeof(last));
for(int i = str.length()-1;i>=0;i--){
for(int j = 0;j<26;j++){
nxt[i][j] = last[j];
}
last[str[i]-'a'] = i;
}
int n;
cin>>n;
while(n--){
string s;
cin>>s;
int pos = last[s[0]-'a'];///先手动找到第一个起始位置,后面迭代即可
bool ok = ~pos;
for(int i = 1;i<s.length() && ok;i++) ok = ~(pos = nxt[pos][s[i]-'a']);
if(ok) cout<<"Yes"<<'\n';
else cout<<"No"<<'\n';
}
return 0;
}
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16379181.html