《戰錘:末世鼠疫2》四週年紀念 活動截止到21日
阿新 • • 發佈:2022-03-09
首先是 KMP 。
設 \(a\) 是長度為 \(n\) 的原串, \(b\) 是長度為 \(m\) 匹配串。
暴力:
for(register int i=1;i<=n;i++)//列舉起點
for(register int j=1;j<=m;j++)
{
if(s[i+j-1]!=p[j])break;
if(j==m)printf("%d\n",i);
}
設 \(nxt\) 表示在 \(p\) 中,以 \(p_i\) 結尾的字尾,能夠匹配的從 \(1\) 開始的 \(\color{red}{非平凡}\) 字首的最大長度。
非平凡代表不是原串子集。
加過 \(nxt\)
部分1:求 \(nxt\) 的過程。
首先一定的是 \(nxt_0=nxt_1=0\) 。
for(register int i=2,j=0;i<=lb;i++)//現在起點是i,匹配到j
{
while(j&&b[i]!=b[j+1])j=nxt[j];//如果開始都不等於,那就直接跳
if(b[i]==b[j+1])j++;//如果匹配成功了,就可以匹配下一位
nxt[i]=j;//當前最多匹配j位
}
接下來嘗試像暴力一樣匹配,如果失配,就直接跳到 \(nxt_j\) 。
for(register int i=1,j=0;i<=la;i++)//起點是i,b匹配到j位 { while(j&&a[i]!=b[j+1])j=nxt[j];//同上,直接跳 if(a[i]==b[j+1])j++;//匹配,下一位 if(j==lb)//全部匹配到了 { printf("%d\n",i-lb+1); j=nxt[j];//還是得跳 } }
程式碼實現:
#include<bits/stdc++.h> using namespace std; const int MAXN=1e6+5; string a,b; int la,lb; int nxt[MAXN]; int main() { cin>>a>>b; la=a.size(),lb=b.size(); a=" "+a,b=" "+b; for(register int i=2,j=0;i<=lb;i++) { while(j&&b[i]!=b[j+1])j=nxt[j]; if(b[i]==b[j+1])j++; nxt[i]=j; } for(register int i=1,j=0;i<=la;i++) { while(j&&a[i]!=b[j+1])j=nxt[j]; if(a[i]==b[j+1])j++; if(j==lb) { printf("%d\n",i-lb+1); j=nxt[j]; } } for(register int i=1;i<=lb;i++) printf("%d ",nxt[i]); return 0; }