1. 程式人生 > >【算法】串的模式匹配算法

【算法】串的模式匹配算法

復雜 get code enter 兩種 否則 進行 htm kmp算法

??串(又稱字符串)是由n(n≥0)個字符組成的有限序列,它是數據元素為單個字符的特殊線性表。串可以用順序存儲方式或者鏈式存儲方式進行存儲。模式匹配是串最重要和最復雜的一個操作,其實也就是串的查找,其中Brute-Force算法和KMP算法是兩種最經常使用的順序存儲結構下的串的模式匹配算法
??模式匹配操作的具體含義是:
??在主串(也稱做目標串)S中,從位置start開始查找是否存在子串(也稱做模式串)T,如果在主串S中查找到一個與模式串T相同的子串,則稱查找成功;如在主串S中未找到一個與模式串T相同的子串,則稱查找失敗。當模式匹配成功時,函數返回模式串T的第一個字符在主串S中的位置;當模式匹配失敗時,函數返回-1。

??實際上,這就是C語言的 strstr() 以及 Java的 indexOf()函數實現的功能。


Brute-Force算法

??BF算法的主要思想是:將主串S的第start個字符和模式T的第1個字符比較,若相等,繼續逐個比較後續字符;若不等,從主串S的下一字符起,重新與T第一個字符比較,直到主串S的一個連續子串字符序列與模式T相等。返回值為S中與T匹配的子序列第一個字符的序號,即匹配成功。否則,匹配失敗,返回值 –1。

    代碼實現:
    public int BFindex(String S,int start,String T){
        int i=start,j=0,v;
        while(i<S.length() && j<T.length()){
            if(S.charAt(i)==T.charAt(j)){
                i++;
                j++;
            }
            else{
                i=i-j+1; //i的下一個,已經比較了j次,所以是i-j+1
                j=0;
            }
        }
        if(j==T.length()) //匹配成功
            v=i-j;
        else v=-1; //匹配失敗
        return v;
    }

??例如,主串T為:ababcabababab,子串為ababa,上述過程如下圖所示。

技術分享圖片

KMP算法

??BF算法簡單並且容易理解,但是有些情況下時間效率不高,最好情況下(一配就中)時間復雜度為O(m),最壞情況下時間復雜度為O(n×m)
??為了克服主串下標i在若幹個字符序列比較相等後,只要有一個字符比較不相等便需要把下標i的值回退的缺點,提出了改進的匹配算法KMP。
??KMP算法的主要思想是:利用已經部分匹配這個有效信息,保持i指針不回溯,通過修改j指針,讓模式串盡量地移動到有效的位置,重點就在於當某一個字符與主串不匹配時,我們應該知道j指針要移動到哪裏
??這可以分為兩種情況來考慮:當前si和tj比較不相等,(1)當模式串中不存在可相互重疊的真子串,下一次可直接比較si和t0;(2)當模式串中存在可相互重疊的真子串時,j要移動的下一個位置為k,k滿足:模式串中最前面的k個字符和j之前的最後k個字符是一樣的。

??所以,問題的重點:計算每一個位置j對應的k,所以用一個數組next來保存,next[j] = k,表示當S[i] != T[j]時,j指針的下一個位置

    求next的函數設計:
    public void getNext(String T,int[] next){
        next[0]=-1; //特殊值
        int j=0,k=-1;

        while(j<T.length()-1){
            if(k==-1 || T.charAt(j)==T.charAt(k))
                next[++j]=++k;
            else
                k=next[k];
        }
    }

??示意圖如下:

技術分享圖片

??當next數組求出後,KMP算法實現也就比較容易,具體代碼如下:

    public int KMP(String S,int start,String T,int [] next){
        int i=start,j=0,v;
        while(i<S.length() && j<T.length()){
            if(S.charAt(i)==T.charAt(j)){
                i++;
                j++;
            }
            else if(j==0) i++;
            else j=next[j];
        }
        if(j==T.length()) 
            v=i-j;
        else v=-1;
        return v;
    }

??示意圖如下:

技術分享圖片

相關鏈接

詳解KMP算法
字符串的模式匹配

【算法】串的模式匹配算法