由于本蒟蒻刚学算法,所以用了个基础的做法,跑了138ms,内存1892K
之后学习了题解中的方法,内存比第一种方法大十倍,但运行时间短了一点,(数据少的原因吧)
收获颇丰,orz
题意
给定字符串s1,有n次查询,每次查询给出一个字符串s2,问s2是否是s1的子序列。
思路
把s2中的字母按顺序在s1中查询,找到一个后则往后接着找,看能否都找到。
代码
1、暴力
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+5; int n; char s1[maxn],s2[maxn]; int main(){ scanf("%s",s1); int len1=strlen(s1);//计算s1的长度 scanf("%d",&n); while(n--){ scanf("%s",s2); int j=0; int len2=strlen(s2);//计算s2的长度 for(int i=0;i<len1;i++){ if(j==len2) break;//s2中的字母全部在s1中找到,结束循环 else if(s1[i]==s2[j]) ++j;//找到一个字母,然后去找下一个 } if(j==len2) printf("Yes\n"); else printf("No\n"); } return 0; }
2、枚举优化(刚学了题解中的方法,毕竟我太菜)
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+5; int n,last[30],nex[maxn][30]; char s1[maxn],s2[maxn]; void solve1(){ int len1=strlen(s1); memset(last,-1,sizeof(last));//-1表示不存在 for(int i=len1-1;i>=0;i--){ for(int j=0;j<26;j++) nex[i][j]=last[j];//将last['a'...'z']复制给当前的next[i]['a'...'z'] last[s1[i]-'a']=i;//当前字母修改last } } bool solve2(){ int len1=strlen(s1),len2=strlen(s2); int i=last[s2[0]-'a'];//i初值直接赋为A中子串首字母的位置 if(i==-1) return 0;//如果A中没有这个首字母 直接无解 for(int j=1;j<len2;j++){//j遍历子串中的字母(首字母就不必了) i=nex[i][s2[j]-'a'];//i跳到前一个字母后面的当前字母 if(i==-1) return 0; } return 1; } int main(){ scanf("%s",s1); solve1(); scanf("%d",&n); while(n--){ scanf("%s",s2); if(solve2()) printf("Yes\n"); else printf("No\n"); } return 0; }