题目描述
给出两个字符串s1 和 s2,若 s1 的区间 [l,r] 子串与 s2 完全相同,则称 s2 在 s1 中出现了,其出现位置为 l。
现在请你求出 s2 在 s1 中所有出现的位置。
定义一个字符串 s 的 border 为 s 的一个非 s 本身的子串 t ,满足 t 既是 s 的前缀,又是 s 的后缀。
对于 s2,你还需要求出对于其每个前缀 s 的最长 border t 的长度。
输入格式
第一行为一个字符串,即为 s1。
第二行为一个字符串,即为 s2。
输出格式
首先输出若干行,每行一个整数,按从小到大的顺序输出 s2 在 s1 中出现的位置。
最后一行输出 ∣s2∣ 个整数,第 i 个整数表示 s2 的长度为 i 的前缀的最长 border 长度。
输入输出样例
输入
ABABABC
ABA
输出
1
3
0 0 1
题意分析就是让我们先找出第二的前后缀最长的公共子串,然后输出,最后利用这个找到第二个字符串在第一个字符串里面的位置,输出即可,kmp,这种思想要理解。具体思想看代码。
#include<bits/stdc++.h> const int MAXN=1e7+10; using namespace std; int kmp[MAXN]; int la,lb,j; char a[MAXN],b[MAXN]; int main() { cin>>a+1;//输入字符串s1 意思就是从下标1 cin>>b+1;//输入字符串s2 la=strlen(a+1);//长度相当于有几个字母注意 lb=strlen(b+1); for (int i=2;i<=lb;i++)//j控制kmp[j] 要小 { while(j&&b[j+1]!=b[i])//j不为0且如果不相邻就跳到前一个前缀里面把j j=kmp[j]; if(b[j+1]==b[i])//如果相等 j++; kmp[i]=j;//前缀数 } j=0; for(int i=1;i<=la;i++) { while(j>0&&b[j+1]!=a[i]) j=kmp[j]; if (b[j+1]==a[i]) j++; if (j==lb) { cout<<i-lb+1<<endl; j=kmp[j];//回溯把kmp的前缀拿出来 } } for (int i=1;i<=lb;i++) cout<<kmp[i]<<" ";//打印的是每个数的前缀 }