考慮字串匹配問題。
假設文字是乙個長度為n
nn的字串t
tt,模板是乙個長度為m
mm的字串p
pp,且m≤n
m≤nm≤
n。尋找匹配點使得t[i
]=p[
0]..
..t[
i+m−
1−1]
=p[m
−1]t[i]=p[0]....t[i+m-1-1]=p[m-1]
t[i]=p
[0].
...t
[i+m
−1−1
]=p[
m−1]
樸素方法:列舉起點,暴力比較,並且一旦不相同就退出。
複雜度:o(m
n)o(mn)
o(mn
)k mp
kmpkm
p具體操作為:求出每個點的字尾和開頭開始的字首最大相同區域是多少。
假如說aaa
abbb
bbaa
acaaaabbbbbaaac
aaaabb
bbba
aac開頭開始和結尾c往前(不包括c)開始最大相同區域為aaa,也就是說如果到了c失配,我可以直接從第4個a開始繼續匹配。(因為aaa已經匹配過了)。
這個時候回頭去看那張圖就很容易懂了。
如何求這個每個點的最大前字尾呢?
對於每個點,求出答案後,對於下乙個點如果相同的話,可以繼續擴大,否則的話迭代失配直到相同為止。
具體**:
#include
#define ll long long
#define inf 0x3f3f3f3f
using
namespace std;
char t[
1000060
],p[
1000050];
int f[
1000050];
void
getfail
(char
* p,
int* f)
}void
find
(char
* t,
char
* p,
int* f)
}int
main()
kmp
kmpkm
p中的字首陣列另乙個應用就是迴圈節:
因為k mp
kmpkm
p有個特殊性質。
y yy
yyxx
xyyy
yyyyyy***yyyy
yyyyyx
xxyy
yyy yy
yyxx
xyyy
y\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ yyyyy***yyyy
yyyyyx
xxyy
yy最大前字尾是這樣的形式。字首陣列求出來之後對於這種情況,從左到右可以分為abc
deabcde
abcd
e五個區域。
首先c
cc區域是一樣的,a=c
2=c1
=e,b
=′yx
xx′=
da=c_2=c_1=e,b='y***'=d
a=c2=
c1=
e,b=
′yxx
x′=d
那麼容易得到的是:a+b
=c2+
da+b=c_2+d
a+b=c2
+d顯然這是是個迴圈節,最後的部分e
ee也一定是迴圈節的字首。
對於乙個字串,直接迭代求末尾的字首函式,就能求出所有迴圈節。(不過末尾可能只有迴圈節的點前面一小串)。
如果必須要求完全迴圈,那麼判斷是否滿足len
/(le
n−f[
x])len/(len-f[x])
len/(l
en−f
[x])
沒有餘數。迴圈節是上方的a+b
a+ba+
b區域。
迭代的一次求出的一定是最小迴圈節,因為此時字首陣列值最大。
例題:
#include
#define ll long long
#define inf 0x3f3f3f3f
using
namespace std;
char t[
1000060
],p[
1000050];
int f[
1000050];
void
getfail
(char
* p,
int* f)
}int
main()
}
KMP演算法小析
對於串的模式匹配演算法,相信學data structure的都不會很陌生,不過當我們看到各種書上對演算法kmp的講解時,我們會有種不知所云的感覺就算有的c 的演算法實現,和例子的講解,當換成另外乙個串時,我們將無從下手,其中對next的求解,更讓我們痛苦。在這裡sinpoal將自己對這個演算法的看法...
KMP演算法簡析
首先,kmp演算法是解決字串匹配問題的演算法,即在主串 s 中查詢子串 t。我們從問題入手,要在主串中查詢子串,顯然可以是用蠻力法逐個遍歷,即從主串的第乙個字元開始和子串的第乙個字元比較,若相等則繼續比較後續字元,若果不相等,則從主串的下乙個的字元 子串的第乙個字元重新開始比較。如果在主串遍歷完之後...
看毛片(KMP)演算法簡析
看毛片演算法又稱kmp演算法。該演算法之所以得名無外乎如下原因。每當涉及該演算法都甚新鮮,極想把玩一番,經過一番琢磨,終於悟透其本質。遂將其束之高閣,數月之後,再相邂逅,新鮮如初,又是一番把玩 醒悟 遺忘,如此迴圈以至無窮。足見,該演算法與看毛片的道理一脈相承。初看新鮮刺激,觀摩研究,醒悟不過如此而...