暖 墟 KMP 模式匹配的演算法流程

2021-08-21 14:09:20 字數 3496 閱讀 6232

字串匹配。給你兩個字串,尋找其中乙個字串是否包含另乙個字串。

如果包含,返回包含的起始位置。如下面兩個字串:

char *str = "bacbababadababacambabacaddababacasdsd";

char *ptr = "ababaca";

str有兩處包含ptr。分別在str的下標10,26處。

我們從原始字串str(假設長度為n)的第乙個下標、

選取和ptr長度(長度為m)一樣的子字串進行比較。

如果一樣,就返回開始處的下標值,不一樣,選取str下乙個下標。

繼續選取長度為m的字串比較,直到str的末尾(即下標移動到n-m)。

這樣的時間複雜度是o(n*m)

kmp演算法:可以實現複雜度為o(m+n)。

充分利用了目標字串ptr的性質(比如裡面部分字串的重複性,

即使不存在重複字段,在比較時,實現最大的移動量)。

考察目標字串ptr:ababaca

這裡我們要計算乙個長度為m的轉移函式next

next陣列的含義就是乙個固定字串的 最長字首 和 最長字尾 相同的長度

比如:abcjkdabc,那麼這個陣列的最長字首和最長字尾相同必然是abc。

cbcbc,最長字首和最長字尾相同是cbc。

abcbc,最長字首和最長字尾相同是不存在的。

預處理的陣列next:next [ i ]表示「str中以i結尾的非字首字串(上文說的字尾)」

「str的字首」能夠匹配到的最長長度

// a="ababacb"; 長度為m

// b="abababaababacb"; 長度為n

(注意:以下**的字串輸入都從1開始)

//next[i]

next[1]=0; j=0;

for(int i=1;i0&&a[i+1]!=a[j+1]) j=next[j];

//↑自身無法繼續匹配且j還沒減到0,考慮返回匹配的剩餘狀態

if(a[i+1]==a[j+1]) j++; //這一位匹配成功

next[i+1]=j; //記錄這一位向前的最長匹配

}

陣列f:f [ i ] 表示「 ptr中以 i 結尾的子串 」「 str的字首 」的最長匹配長度。

在b串中尋找a串出現的位置:

j=0;

for(int i=0;i0) j=next[j];

//↑不能繼續匹配且j還沒減到0(之前的匹配有剩餘狀態)

if(b[i+1]==a[j+1]) j++; //匹配加長,j++

if(j==m) //【↑↑巧妙↑↑這裡不用返回0,只用返回上一匹配值】

}

求f陣列(a與b最大的匹配長度):

//f[i]

j=0;

for(int i=0;i0) j=next[j];

//↑不能繼續匹配且j還沒減到0(之前的匹配有剩餘狀態)

//↑↑↑或a在b中找到完全匹配

if(b[i+1]==a[j+1]) j++; //匹配加長,j++

f[i+1]=j; //此位置和先前組成的最長匹配

// (if(f[i+1]==m),此時a在b中找到完全匹配)

}

(1)剪花布條(hdu2087)

#include #include #include #include #include #include #include #include #include using namespace std;

typedef long long ll;

typedef unsigned long long ull;

//【剪花布條】能從花布條中剪出多少小花條? [注意:不能重疊!]

char a[1009],b[1009];

int nextt[1009],n,m;

void pre()

}int kmps() //j=0,保證不重疊

if(b[j+1]==a[i+1]) j++; //匹配加長,j++

}return ans;

}int main()

return 0;

}

(2)字串週期(poj 2406)

#include #include #include #include #include #include #include #include #include using namespace std;

typedef long long ll;

typedef unsigned long long ull;

/*【power strings】poj2406

給出乙個不超過1e6的字串,求這個字串最多有多少個週期。 */

char a[1000005];

int nextt[1000005],n;

void pre()

}int main()

return 0;

}

(3)最小迴圈元長度和最大迴圈次數(poj1961)

#include #include #include #include #include #include #include #include #include using namespace std;

typedef long long ll;

typedef unsigned long long ull;

/*【period】poj 1961

給你乙個字串,求這個字串到第i個字元為止的最小迴圈元長度和最大迴圈次數。 */

char a[1000005];

int nextt[1000005],n,t;

void pre()

}int main()

printf("\n");

}return 0;

}

(4)bzoj 1355/1511/3620/3942

【等待填坑中σ( ° △ °|||)︴】

暖 墟 AC自動機 多模式串的匹配運用

1.將所有模式串構建成 trie 樹 2.對 trie 上所有節點構建字首指標 類似kmp中的next陣列 3.利用字首指針對主串進行匹配 字典樹的構建過程是這樣的,當要插入許多單詞的時候,我們要從前往後遍歷整個字串,當我們發現當前要插入的字元其節點再先前已經建成,我們直接去考慮下乙個字元即可,當我...

模式匹配 KMP演算法

字串匹配演算法 include includeusing namespace std define ok 1 define error 0 define overflow 2 typedef int status define maxstrlen 255 使用者可在255以內定義最長串長 typed...

模式匹配KMP演算法

前些日子在為目前該學習什麼而苦惱,就問了一下已經從事多年軟體開發的表哥,他說乙個程式設計師要走的遠,就要學好資料結構和演算法,於是我就重新開始學習資料結構和演算法了 拿起以前上過的資料結構看,看到第四章串的模式匹配時,頗感興趣,就寫了一下程式,實踐了一下。感覺還蠻爽,於是就把以下幾個重要的函式放在此...