1. 程式人生 > >KMP算法-從入門到進階

KMP算法-從入門到進階

alt 模式串 移動 分享 進階 有意 什麽 比較 最後一個元素

題目描述

給定一個文本串text和模式串pattern,從文本串中找出模式串第一次出現的位置

技術分享圖片

先來看最簡單的方法,方便理解題目,也就是暴力求解

暴力求解

放大上面的圖,得到下面這個。題目要求匹配到整個字符串,從開始匹配考慮。

技術分享圖片

用模式串的首元素去匹配文本串的每一個元素,如果能匹配到,則依次向後匹配,直到所有的模式串匹配成功。

如果模式串中有一個不匹配,則pattern回到首元素匹配test中的下一元素。

這裏需要註意的是,模式串首元素需要匹配的最後一個元素是text-j,因為如果匹配到最後,模式串比text長是沒有意義的。

整個流程,可以想象是先把模式串與text對齊,然後相對於text依次後移一位,拖動pattern,每次移動都比較整個pattern模式串每個元素(理解這個有助於後面分析)

關鍵代碼如下

int search(const char*s, const char*p)
{
    int i = 0;//用於標記匹配到text字符串的位置
    int j = 0;//標記模式串中匹配的位置
    int size = (int)strlen(p);
    int nLast = (int)strlen(s) - size; //此處為匹配到text中最長位置
    while((i <=  nLast) && (j < size))
    {
        if (s[i+j] == p[j])
        {
            j ++;
        }
        else{
            i++;
            j = 0; //j回到模式串首元素
        }
    }
    if(j >= size)
        return i;
    return -1;
}

記text長度為N,pattern長度為M。在這個方法中,時間復雜程度為O(M*N),空間復雜程度為O(1)

進一步分析:

在暴力求解中,為什麽模式串的索引 j 會回溯?原因是模式串需要依次匹配整個才能知道是否完全匹配。

所以,增加一個條件,如果模式串的字符兩兩不相等。也就意味著模式串只要一次不匹配,整個 j 的長度都不會匹配上,就可以向後拖動pattern到自身長度的位置。

即,如果發生了不匹配,則向後移動 i+j 個位置開始匹配。

現在整個算法的時間復雜度退化成了O(N),但這是在模式串兩兩不等的情況下才有的結論。那這個條件可以弱化嗎?

當然是可以,弱化後條件變為:模式串首字符和其他字符不相等。

KMP算法-從入門到進階