原题连接ios
题目:数组
给定一个模式串S,以及一个模板串P,全部字符串中只包含大小写英文字母以及阿拉伯数字。spa
模板串P在模式串S中屡次做为子串出现。指针
求出模板串P在模式串S中全部出现的位置的起始下标。code
输入格式ci
第一行输入整数N,表示字符串P的长度。字符串
第二行输入字符串P。get
第三行输入整数M,表示字符串S的长度。io
第四行输入字符串S。模板
输出格式
共一行,输出全部出现位置的起始下标(下标从0开始计数),整数之间用空格隔开。
数据范围
1 ≤ N ≤ 10^5
1 ≤ M ≤ 10^6
输入样例:
3 aba 5 ababa
输出样例:
0 2
解题代码:
#include <iostream> #include <cstdio> using namespace std; const int N = 100010, M = 1000010; char p[N], s[M]; int ne[N]; int n,m; int main(){ cin >> n >> p + 1 >> m >> s + 1; //初始化next数组(寻找模板串中最长的公共先后缀) for(int i = 2, j = 0; i <= n; i++){ while(j && p[i] != p[j + 1]) j = ne[j]; //前缀与后缀匹配失败,使j回退到以前找到的公共先后缀的长度的位置,直到 p[i] 和 p[j + 1]匹配 或 j 回退到了起点(0的位置)。 if(p[i] == p[j + 1]) j++; //前缀的i下标元素和后缀的j+1下标元素匹配成功,并继续匹配下一个 ne[i] = j; //前i个数中的最长公共先后缀的长度为j,标记j的位置,以用来以后将j回退 } //开始匹配 for(int i = 1, j = 0; i <= m; i++){ while(j && s[i] != p[j + 1]) j = ne[j]; if(s[i] == p[j + 1]) j++; if(j == n){ printf("%d ", i - n); j = ne[j]; //j指针回退,继续寻找下一个能匹配的位置 } } return 0; }