给定一个模式串S,以及一个模板串P,所有字符串中只包含大小写英文字母以及阿拉伯数字。
模板串P在模式串S中多次作为子串出现。
求出模板串P在模式串S中所有出现的位置的起始下标。
输入格式
第一行输入整数N,表示字符串P的长度。
第二行输入字符串P。
第三行输入整数M,表示字符串S的长度。
第四行输入字符串S。
输出格式
共一行,输出所有出现位置的起始下标(下标从0开始计数),整数之间用空格隔开。
数据范围
1≤N≤1041≤N≤104
1≤M≤1051≤M≤105
输入样例:
3
aba
5
ababa
输出样例:
0 2
##############################################
1 #include <iostream> 2 3 using namespace std; 4 5 const int N = 1e4+10, M = 1e5+10; 6 7 char p[N], s[M]; 8 int ne[N];//ne数组,代表从起点到长度为 i 的最长公共前后缀长度 9 10 int main(){ 11 int n, m; 12 cin >> n >> p + 1 >> m >> s + 1;//下标从 1 开始 13 ne[0] = 0; 14 ne[1] = 0; 15 for(int i = 2;i <= n;++ i){ 16 int tmp = i - 1;//找到i的前一个位置 17 do tmp = ne[tmp];//求出从起点到i的前一个位置的最长公共前后缀 18 while(tmp != 0 && p[i] != p[tmp + 1]);//因为最长公共前后缀等于0可能会导致死循环, 19 //另外一个判断条件是i位置的数和最长公共前后缀的下一个数不相等 20 if(p[i] == p[tmp + 1])ne[i] = tmp + 1;//下面的if else很巧妙的处理了使上面的循环退出的两种情形 21 else ne[i] = 0; 22 } 23 //i 代表 s , j 代表 pat 24 //用j+1去作比较,一个技巧(记住) 25 for(int i = 1, j = 0;i <= m;++i){ 26 if(s[i] == p[j+1]) ++j; 27 else{ 28 do j = ne[j]; 29 while(j != 0 && p[j + 1] != s[i]); 30 if(p[j + 1] == s[i]) ++j; 31 else j = 0; 32 } 33 if(j == n){ 34 cout << i - n<< " "; 35 j = ne[j]; 36 } 37 } 38 39 40 return 0; 41 }
end