【算法題】字符串匹配算法KMP

詳解見博客

KMP算法

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

vector<int> GetNext(string str)
{
    vector<int> next(str.size());
    //next數組含義:如果str[i]不匹配,在str[i]之前:next[i]個後綴與 next[i]個前綴是相同的,(前綴和後綴是不能等於字符串本身的)
    //所以應該跳轉到(str[next[i]])處,這樣可以將next[i]個前綴與後綴完全重合,繼續比較
    //next[i]存的是 str[i] 的第一長的相同前綴後綴的長度,
    //next[next[i]]存的是 str[i] 的第二長的相同前綴後綴的長度...依次類推
    if (str.empty())
        return next;

    int j = 0;
    int k = -1;
    next[j] = k;
    //str[j]爲後綴最後一位,str[k]爲前綴最後一位
    //如果str[0]不匹配,str[0]前:有0個後綴與0個前綴相同,所以應該跳轉到(0)處
    //但是str[0]==str[0],所以next[0]存放-1,當調整到str[-1]時,意味着需要整體右移一位
    while (j<str.size()-1)
    {
        if (k == -1||str[j]==str[k])
        {
            ++k;//最長前綴後綴加1:k+1
            ++j;//存到next數組的j+1處
            next[j] = k;
        }
        else
        {
            k = next[k];
        }
    }

    //去除無效跳轉,如果當前字符不匹配,且跳轉後的字符和當前字符一樣,則調整後肯定還是不匹配,需要繼續跳轉
    for (auto i = 0; i < next.size();++i)
    {
        int k = next[i];
        while (k != -1 && str[i] == str[k])
        {
            k = next[k];
        }
        next[i] = k;
    }
    return next;
}

int KMPSearch(string str, string pstr)
{
    vector<int> next = GetNext(pstr);

    int i = 0, j = 0;

    int slen = str.size();
    int plen = pstr.size();
    while (i < slen&&j < plen)
    {
        if (j == -1 || str[i] == pstr[j])
        {
            ++i;
            ++j;
        }
        else
        {
            j = next[j];
        }
    }
    if (j == pstr.size())
    {
        return i - j;
    }
    else
    {
        return -1;
    }
}

int main()
{
    string pstr = "abab";
    string str = "asdfafasfaababfasgdga";
    cout<<KMPSearch(str, pstr)<<endl;

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