luogu p3375
對於字串匹配,有一種很顯然的樸素演算法:在s1中列舉起點一位一位匹配,失配之後起點往後移動一位,從頭開始進行匹配。
這種演算法的時間複雜度幾乎達到了\(o(nm)\),顯然是不能接受的。
這種做法的缺點在於做了很多無用的匹配,並且每一次都從頭開始匹配,完全忽略上一次匹配的資訊。
而kmp演算法就利用了上一次匹配的資訊,減少匹配次數,時間複雜度僅有\(o(n)\)
(來自演算法導論)
觀察這樣一張圖。在第六位失配之後,按照樸素演算法,我們把模式串後移一位,從頭開始匹配。事實上後移一位的匹配根本不可能成功,根據上一次匹配得到的資訊,因為文字串(灰色部分)中的第二位能夠與模式串的第二位匹配,所以不可能與第一位匹配。而文字串(灰色部分)第三四五位恰好與模式串的第一二三位匹配,所以我們可以直接把模式串後移兩位,重新開始匹配。
(來自演算法導論)
如上圖所示,這樣可以減少很多不必要的匹配。
那麼我們怎麼才能知道讓模式串偏移多少才合適呢?
下文的j是在模式串中的指標,j及其以前的字元是已經匹配的。
假設字串在第j位失配,我們要找到乙個盡可能長的長度\(l\),使\(s2[1..l]\)與\(s2[j-l,j]\)完全匹配(l\(j=l\),跳過前面l個的字元,因為他們絕對是匹配的。
結合**及注釋進行透徹的理解:(從kmp函式開始看更便於理解)
#include#includeusing namespace std;
string s1,s2;
int nxt[1000005];
void pre_do()
}int kmp()
} return ret;
}int main()
luoguP3375 模板 KMP字串匹配
如題,給出兩個字串s1和s2,其中s2為s1的子串,求出s2在s1中所有出現的位置。為了減少騙分的情況,接下來還要輸出子串的字首陣列next。輸入格式 第一行為乙個字串,即為s1 第二行為乙個字串,即為s2 輸出格式 若干行,每行包含乙個整數,表示s2在s1中出現的位置 接下來1行,包括length...
Luogu P3375 模板 KMP字串匹配
如題,給出兩個字串s1和s2,其中s2為s1的子串,求出s2在s1中所有出現的位置。為了減少騙分的情況,接下來還要輸出子串的字首陣列next。輸入格式 第一行為乙個字串,即為s1 第二行為乙個字串,即為s2 輸出格式 若干行,每行包含乙個整數,表示s2在s1中出現的位置 接下來1行,包括length...
luogu P3375 KMP字串匹配 模板
精華 在每次失配後不從頭匹配而是嘗試找乙個新的開始並且是新開始的位置最長的相同字首和字尾。實際上kmp是一種自己匹配自己的模式。好好理解qaq include include include include using namespace std const int maxn 1000001 cha...