【數據結構】KMP算法


目錄

KMP時間複雜度 

match函數

match的實現

match的時間複雜度

具體代碼實現:



KMP要求模式串一頭一尾能匹配上

 

解釋: j=6時候,match = 3,意思是p0-p3是能夠和p(6-3)-p6匹配。


注意:當有一個串能配得上,並不能到此爲止,要繼續檢查還有沒有更長的串。

KMP時間複雜度 

match函數

 

優秀的做法:

首先j-1位置和match【j-1】位置匹配

然後考慮j位置和match[j-1]+1位置是否匹配?如果匹配

如果match[j]>match[j-1]+1,考慮向前一個位置A

如果能匹配,則後面字符都能匹配。

一旦出現這種情況,意味着A-X能匹配上,意味着對於0到j-1這個子串來說他的macth值應該指向X,match[j-1]+1的位置。這是不可能的。用反證法證明:

                                                          match[j] = match[j-1]+1

當j位置和match[j-1]+1不匹配,查看前match[j-1]是否有匹配的

遞歸的查看

比較兩個?的位置,即比較j和match[match[j-1]] +1(回溯)

如果能夠匹配

match[match[j - 1]] +1 = match[j]

match的實現

match的時間複雜度

O(m)平方是上界

 

具體代碼實現:

#include <iostream>
#include <vector>
#include <string>
using namespace std;

vector<int> buildMatch(string p) {
    int len = p.size(), k = -1, j = 0;//k表示和j匹配,也表示匹配從0到k 
    vector<int> match(len, -1);//初始化爲-1

    while (j < len - 1) {
        if (k == -1 || p[j] == p[k]) {
            ++k; ++j;
            match[j] = (p[j] != p[k]) ? k : match[k];//要避免出現p[j] == p[match[j]]的情況
        } else {
            k = match[k];
        }
    }
    return match;
}

int kmp(string s, string p) {
    int m = s.size(), n = p.size();
    if(m < n) return -1;
    
    vector<int> match = buildMatch(p);
    int i = 0, j = 0;
   
    while (i < m && j < n) {
        if (j == - 1 || s[i] == p[j]) {
            ++i; ++j;
        } else {
            j = match[j];
        }
    }
    return (j == n) ? i - j : -1;
}

int main() {
	string s,p;
	cin>>s>>p;
    cout << kmp(s, p) << endl;  
}

 

參考:https://www.bilibili.com/video/BV1zJ411E7cg?p=146

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章