KMP算法

ypwq5767 8年前發布 | 16K 次閱讀 算法

來自: http://www.cnblogs.com/tonychen-tobeTopCoder/p/5170246.html

看嚴蔚敏的數據結構看得云里霧里,后來看了 其它博客 才了解得比較透徹。其實算法的大體思路并不難理解。最原始的字符串匹配算法是將匹配串與模式串對齊,然后從左向右一個個比較,如果失配則模式串向右移動一個單位,這樣沒有利用前面部分匹配的信息,時間復雜度為O(n*m)。

KMP算法則是利用了部分匹配的信息,并以此來判斷失配時向右移動多少,時間復雜度為O(n+m)。設i指向匹配串的當前匹配字符,j指向模式串的當前匹配字符,若失配,則j=next[j]。

因此關鍵就是求模式串的next數組。嚴蔚敏的教材是針對從1開始的數組的,而且對next數組的值的意義也沒說清楚,所以在那里卡了很久,看了其他人的博客才清楚。

要理解next數組還是比較難的,教材上的思路是這樣的:

已知next[0]=-1,next[1]=0,設next[j]=k,若t[j]==t[k]且t[j+1]!=t[k+1],則next[j+1] =next[j]+1;若t[j]==t[k]且t[j+1]==t[k+1],則next[j+1] = next[k+1]。若t[j]!=t[k],可以看成模式串自身匹配問題,將模式向右滑動到next[k],若還是不匹配,就滑動到next[next[k]],如果最后還是不匹配則就肯定會滑動到next[0]。所以下面的程序會看到if(j ==-1 ||...)

next數組的取值(設模式串為t[])

next[0]=-1 任何模式串的第一個模式值規定為-1

next[j] = -1 (j>k≥1) 若t[j] = t[0]且前k個字符不等于j前面的k個字符,則模式值為-1(這表示第一個字符都無法匹配)

next[j] = k   (j>k≥1)t[j]!=t[k]且前k個字符等于j前面的k個字符

next[j] = 0  其它情況。這里有三種情況,一種是對于j>k≥1,前k個字符不等于j前面的k個字符且t[j]!=t[0],自然需要滑動到第一個字符再開始匹配;一種是對于j>k≥1,前k個字符等于j前面的k個字符且t[j]==t[0],讓它直接滑動到第一個字符(因為next[k]會是0),能夠減少比較次數;還有一種就是next[1]總是為0

代碼如下

inline void get_next(string t, int next[])
{
    int i = 0, j = -1;
    next[0] = -1;
    while (i<t.length())
    {//j在每次循環開始都表示next[i]的值,同時也表示需要比較的下一個位置 
        if (j == -1 || t[i] == t[j])
        { 
            ++i; 
            ++j;
            if (t[i] != t[j])
                next[i] = j;
            else
                next[i] = next[j];
        }
        else j = next[j];
    }
}
int KMP(string s, string t)
{
    int i = 0, j = 0;
    int s_len = s.length();
    int t_len = t.length();
    int *next = new int[t_len + 1];
    get_next(t, next);
    while (i<s_len && j<t_len)
    {
        if (j==-1 || s[i] == t[j]) { ++i; ++j; }
        else
            j = next[j];
    }
    if (j>=t_len) return i - t_len; //匹配成功
    else return -1;
}
</div>

 本文由用戶 ypwq5767 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!