kmp中最關鍵的就是通過getnext函式得到next陣列。並且getnext函式也有一點點小區別,我想在此一一枚舉出來,作為模板給自己備用。
重點文章:從頭到尾徹底理解kmp(2023年8月22日版)
最近才理解了為什麼單字元無前字尾:字首不包括字串的最後乙個字元,字尾不包括字串的第乙個字元。
模板一:
說明:next[i]儲存的是第i+2個字元失配後要跳轉的位置,其值等於長度為i+1的字串,即p[0]p[1]……p[i]前字尾的最大相同長度。
在kmp函式中的使用,如果p[j]!=s[i],則j=next[j-1]。
這是next陣列中沒有-1元素的情況,適用於一般的模式匹配,不論是字串還是整型陣列。
int next[maxn]
;void
getnext
(char
* p,
int len)
}
模板二:
說明:next[i]儲存的是第i+1個字元即p[i]失配後要回溯的位置,相當於模板一的next陣列右移乙個單位。next[i]值的大小為除去p[i]後的前i個字元組成的字串,即p[0]p[1]……p[i-1]的最大字首字尾的相同字元數。因此,next[len]也是有值的。
同樣是沒有-1存在的情況,在kmp函式中使用時,若p[j]!=s[i],則j=next[j].
理解next[0]==next[1]==0:第1個字元之前無字元,第2個字元之前只有1個字元,兩者情況均無字首字尾,因此預設為0。
int next[maxn]
;void
getfail
(char
* p,
int plen)
}
模板三:
說明:該getnext的函式是經過優化的版本,匹配的速度可以更快一點。在上述兩個模板中沒有優化。
以模板一為例,若有字串"aaabcdaaa",則next[0],next[1],next[2]是依次遞增的,其值分別為0,1,2,如果p[2]=a和s[x]不匹配,則會跳到p[next[2-1]],即p[1],p[1]仍為a,顯然也和s[x]不匹配,依次進行下去會發現到起點p[0]仍不匹配。
因此可以針對這點進行優化來減少幾次迴圈。優化的方式為當p[i]==p[next[i]]時,next[i]=next[next[i]]。詳細分析可以看**部落格。
//優化過後的next 陣列求法
void
getnextval
(char
* p,
int next)
else
}}
對模板一和模板二進行優化,似乎得next陣列完全生成後再進行,如果邊生成邊優化會使陣列出問題。
for
(int i =
1; i <= plen; i++)if
(p[i]
== p[next[i]
])next[i]
= next[next[i]
];
①hdu - 2087 剪花布條
分析:基礎模板題。
#include
#include
using
namespace std;
const
int maxn =
1000+5
;int next[maxn]
, cnt;
void
getfail
(char
* p,
int plen)
}void
kmp(
char
* s,
char
* p)
else
return;}
}}intmain
(void
)return0;
}
②hdu - 1686 oulipo
分析:該題字串匹配成功後回溯的地方應該是next陣列中的對應元素,而非首字元。
#include
#include
using
namespace std;
const
int maxp =
1e4+5;
const
int maxs =
1e6+5;
int next[maxp]
, ans;
char s[maxs]
,p[maxp]
;void
getnext
(int len)
}void
kmp()}
intmain
(void
)return0;
}
③hdu - 1711 number sequence
分析:int陣列的kmp,和char陣列是一樣的。
#include
#include
using
namespace std;
const
int maxp =
1e4+5;
const
int maxs =
1e6+5;
int next[maxp]
, ans;
int s[maxs]
,p[maxp]
;void
getnext
(int len)
}int
kmp(
int s,
int slen,
int p,
int plen)
if(j < plen)
return-2
;else
return i - j;
}int
main
(void
)return0;
}
④poj - 2406 power strings
這種東西還是挺神奇的,感覺和數學定理一樣,雖然正確但是不會證啊,背就完事了。
**如下:
#include
#include
using
namespace std;
const
int maxn =
1e6+5;
int next[maxn]
;char p[maxn]
;void
getnext
(char
* p)
else
k = next[k];}
if(len %
(len - next[len])==
0)printf
("%d\n"
, len /
(len - next[len]))
;else
printf
("1\n");
}int
main
(void
)return0;
}
⑤poj - 1961 period
分析:上一題的加強版,暴力求解是不能過了。如果理解了上一題,這個也是挺容易的。
#include
#include
using
namespace std;
const
int maxn =
1e6+5;
int next[maxn]
;char p[maxn]
;void
getnext
(char
* p)
}int
main
(void
)return0;
}
拓展KMP演算法 入門 模板
擴充套件kmp演算法,圖很形象,寫的也很清晰,下面的模板就是出自該部落格文章。拓展kmp是求母串s長度為n和子串t長度為m,求s的每乙個字尾子串與t的字首子串匹配的最長長度。求解模式串t的next陣列,這個函式和下面的函式幾乎相同 void getnext string t,int m,int ne...
KMP演算法(模板)
time limit 1000ms memory limit 65536k 有疑問?點這裡 給定兩個字串string1和string2,判斷string2是否為string1的子串。輸入包含多組資料,每組測試資料報含兩行,第一行代表string1 長度小於1000000 第二行代表string2 長...
KMP演算法模板
在文字t 1.n 中找到某個模式p 1.m 所有出現的位置被稱作字串匹配問題 m n p3375 模板 kmp字串匹配 這道題在洛谷上的評級居然是普及 普及?qvq 實現起來還是比較簡單的,只不過有很多細節可以有很多種寫法,看別人的 容易凌亂。理解起來比較困難的部分是如何get next 不建議初學...