部分內容引自皎月半灑花的部落格
模式串匹配問題模型
給定一個需要處理的文字串和一個需要在文字串中搜尋的模式串,查詢在該文字串中,給出的模式串的出現有無、次數、位置等。
演算法思想
每次失配之後不會從頭開始列舉,而會從最大可能匹配位置開始重新匹配
考慮資料
模式串:abcabc
文字串:abcabdababcabc
匹配過程中文字串的$d$和模式串末位的$c$出現了失配,由目前的匹配結果可知模式串的前五位$abcab$與文字串失配位置前的五位匹配,取模式串中匹配的部分$S$,當且僅當$S$中有任何與字尾相同的字首,滿足該字首一定與文字串失配位置前的若干位匹配,取滿足上述條件的最大字首與文字串匹配,再嘗試重新匹配下一位(這一位置即為最大可能匹配位置),重複該過程直到匹配成功或不存在這樣的字首時結束
模式串: abcabc
文字串:abcabdababcabc
$next$陣列
$next[i]$表示前$i-1$位(從第0位開始)匹配而第$i$位失配時應跳轉到的位置,該位置滿足前$next[i]-1$位仍與文字串匹配
$next$陣列的處理
自匹配,使模式串與自身進行匹配,匹配過程中處理出下一位的$next$值,即當前位的最大匹配的後一位
程式碼
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=1e6+10; char s[maxn],st[maxn]; int n,m,nxt[maxn]; void getnext() //自匹配(next陣列的處理) { for(int j=0,i=1;i<m;i++) { while(j&&s[i]!=s[j]) j=nxt[j]; nxt[i+1]=(j+=s[i]==s[j]); //若i,j位置匹配成功,顯然s[1~j]是s[1~i]的最大的,滿足前字尾相等的字首,則j+1為s[i]的最大可能匹配位置 //否則j必為0,意為沒有任何成功的匹配 } } int main() { scanf("%s%s",st,s); n=strlen(st),m=strlen(s); getnext(); for(int j=0,i=0;i<n;i++) //i為文字串位置,j為模式串當前嘗試匹配的位置 { while(j&&st[i]!=s[j]) //重複取最大可能匹配位置,直到匹配成功或不存在任何可能的匹配 j=nxt[j]; if(st[i]==s[j])//若匹配成功,模式串嘗試匹配的位置後移一位 if(++j==m) { printf("%d\n",i-j+2); j=nxt[j]; //若匹配成功則統計答案並重置匹配位置 } } for(int i=1;i<=m;i++) printf("%d ",nxt[i]); printf("\n"); return 0; }