国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

字符串匹配算法之KMP模式

NeverSayNever / 2878人閱讀

摘要:字符串的普通模式匹配普通模式匹配的原理不進(jìn)行說明了,簡單來說就是兩個字符串的每個字符依次進(jìn)行匹配。

這篇文章主要是介紹KMP模式匹配算法,在正式介紹KMP之前我們先看一下普通模式匹配,由普通模式匹配在進(jìn)一步的推導(dǎo)KMP模式會更容易理解。

字符串的普通模式匹配

普通模式匹配的原理不進(jìn)行說明了,簡單來說就是兩個字符串的每個字符依次進(jìn)行匹配。

public int match(String S,String T){
    int i = 0;
    int j = 0;

    while(i < S.length() && j < T.length()){
        if(S.charAt(i) == T.charAt(j)){
            i++;
            j++;
        }else{
            i = i - j + 1;
            j = 0;
        }
    }

    if(j >= T.length()){
        return i - T.length();
    }else{
        return 0;
    }
}

普通模式匹配的時間復(fù)雜度最壞的情況(即T在S的末尾)為O((m-n+1)*n)。這種算法的優(yōu)點(diǎn)是實(shí)現(xiàn)簡單,缺點(diǎn)也顯而易見那就是效率較低。jdk String類內(nèi)的靜態(tài)方法indexOf底層使用的就是類似該種算法。

KMP模式匹配算法推導(dǎo) 回溯推導(dǎo)

為了方便理解KMP模式,我們先看一下普通模式模式的流程:

栗子1:

主串:S = "abcdefgab"

子串:T = "abcdex"

觀察下普通模式匹配算法,對于要匹配的子串T = “abcdex”來說

首字母"a"與后面的串"bcdex"中的任意一個字符都不相等;

串"bcde"與主串S的第2-5位相等,那么首字母"a"就不可能與主串S的第2-5位相等。

所以,第2 3 4 5 的判斷都是不需要的,這是個理解KMP模式的關(guān)鍵。

那么問題來了,如果T串后面還含有首字母"a"的字符會怎么樣呢?我們在看一個例子:

粟子2:

主串:S = "abcabcabc"

子串:T = “abcabx”

對于要比配的子串T = "abcabx"來說,

T的首字母"a"與T的第2個字符"b"、第3個字符"c"均不等,且T的第1-3位字符與主串S的第1-3相等,所以,步驟2和步驟3可以省略;

T的前2位串"ab"與T的第4-5串"ab"相等,且T的第4-5串"ab"與主串S的第4-5串"ab"相等,得出T的前2位串與S的第4-5也相等,可以省略。

最后,第6步的前兩次比較也是不需要的,直接比較 主串S的第6位的"a"和子串T的第3位"c"即可,如下圖:

對比這兩個例子,可以發(fā)現(xiàn)普通模式主串S的游標(biāo)每次都是回溯到i++的位置。而經(jīng)過上面的分析后發(fā)現(xiàn),這種回溯方式其實(shí)是不需要的,KMP模式就是解決了這些沒有必要的回溯。

既然要避免i的回溯,那么我們就要在子串T的游標(biāo)j上下工夫了。通過觀察也可發(fā)現(xiàn),如果T的首字母與自身后面的字符有相等的情況,那j值的變化就會不相同。

例子1內(nèi)j的變化,由于首字母"a"與后面的字符都不相等,則j由6變回了1。

例子2內(nèi)j的變化,由于前綴"ab"與后面的"ab"相等,因此j從6變回了3。

有沒有看出什么規(guī)律?提示一下:

例子1內(nèi)與前綴相同的字符個數(shù)為0,j變成了1。

例子2內(nèi)與前綴相同的字符個數(shù)為2,j變成了3。

j的變化取決也當(dāng)前字符之前的串的前后綴的相似度。

回溯公式

根據(jù)上一節(jié)的推導(dǎo),我們可以將T串各個位置的j的變化定義為一個數(shù)組next,next的長度就是T串的長度,我們可以得到下面的函數(shù)定義(為了后面讀程序方便理解,所以該函數(shù)是遵循數(shù)組下標(biāo)從0開始的規(guī)范):

我們來手工驗(yàn)證一下該函數(shù)。

T = "abcdex"

j 123456
模式串T abcdex
next[j] 000000

if j = 0, next[0] = 0;

if j = 1, "p~0~ ... p~k~" = "p~j-k~ ... p~j~" --> "a" <> "b" ,next[1] = 0;

if j = 2, 子串"abc",也沒有重復(fù)的字符子串,next[2] = 0;

以后同理,所以最終T串的ntxt[j]為000000。

例子就列舉到這里,現(xiàn)在放下KMP的Java實(shí)現(xiàn),其它實(shí)例大家可以使用程序進(jìn)行驗(yàn)證。

KMP模式匹配算法實(shí)現(xiàn)
public void getNext(String T,Integer[] next){
    next[0] = 0;    //當(dāng)j = 0時,next[0] = 0

    int i = 1;
    int j = 0;
    int k = 0;
    while (i < T.length() && j < i){
        if(T.substring(0,j).equals(T.substring(i-j,i))){
            k = j;    //若有相同子串,則記錄下對應(yīng)在T串內(nèi)的位置,最終得出最長匹配成功的位置
        }
        j++;

        if(j >= i){
            next[i] = k;    //若一直未匹配成功,將k = 0賦值給next[i]
            j = 1;
            k = 0;
            i++;
        }
    }
}

我們來測試 幾個字符串:

input: abcdex
output:000000

input: abcabx
output:000012

input: aaaaaaaab
output:001234567

下面是完整的KMP模式匹配算法的代碼:

package string;
public class KMPMatch {
    public void getNext(String T,Integer[] next){
        next[0] = 0;    //當(dāng)j = 0時,next[0] = 0

        int i = 1;
        int j = 0;
        int k = 0;
        while (i < T.length() && j < i){
            if(T.substring(0,j).equals(T.substring(i-j,i))){
                k = j;    //若有相同子串,則記錄下對應(yīng)在T串內(nèi)的位置,最終得出最長匹配成功的位置
            }
            j++;

            if(j >= i){
                next[i] = k;    //若一直未匹配成功,將k = 0賦值給next[i]
                j = 1;
                k = 0;
                i++;
            }
        }
    }

    public int match(String S,String T){
        int i = 0;
        int j = 0;

        Integer[] next = new Integer[T.length()];
        getNext(T,next);

        while(i < S.length() && j < T.length()){
            if(j == 0 || S.charAt(i) == T.charAt(j)){
                i++;
                j++;
            }else{
                j = next[j];
            }
        }

        if(j >= T.length()){
            return i - T.length();
        }else{
            return 0;
        }
    }

    public static void main(String[] args) {
        String S = "aaaabcde";
        String T = "abcd";
        System.out.println(new KMPMatch().match(S,T));
    }
}

對于方法getNext來說,若T的長度為m,因只涉及簡單的單循環(huán),其時間復(fù)雜度為O(m),由于i不進(jìn)行回溯,while循環(huán)的時間復(fù)雜度為O(n)。因此,整個算法的時間復(fù)雜度為O(m+n)。

對于KMP模式來說,僅當(dāng)子串與主串之前存在許多“部分匹配”的時候才體現(xiàn)出它的優(yōu)勢,否則兩者差異并不明顯。

KMP模式匹配算法的優(yōu)化

看下面這個例子:

S = "aaaabcde"

T = "aaaaax"

T的next分別為001234,兩個串的匹配流程如下:

從流程中可發(fā)現(xiàn),當(dāng)中的步驟2 3 4 5都是多余的判斷。由于T串的第2 3 4 5位置的字符都與首字符相等,那么就可以用首位next[0]值去取代與它相等的字符的next[j],下面就是對getNext方法進(jìn)行的改良,代碼如下:

public void getNextVal(String T,Integer[] nextVal){
    nextVal[0] = 0;    //當(dāng)j = 0時,next[0] = 0

    int i = 1;
    int j = 0;
    int k = 0;
    while (i < T.length() && j < i){
        if(T.substring(0,j).equals(T.substring(i-j,i))){
            k = j;    //若有相同子串,則記錄下對應(yīng)在T串內(nèi)的位置,最終得出最長匹配成功的位置
        }
        j++;

        if(j >= i){
            //當(dāng)前字符與前綴字符相同中,則當(dāng)前字符j為nextVal[i]
            if(T.charAt(i) == T.charAt(k)){
                nextVal[i] = nextVal[k];
            }else {
                nextVal[i] = k;
            }
            j = 1;
            k = 0;
            i++;
        }
    }
}

學(xué)習(xí)是一個過程,對學(xué)習(xí)到的知識進(jìn)行理解、吸收、整理,并將其按自己的理解進(jìn)行輸出。

參考材料:《大話數(shù)據(jù)結(jié)構(gòu)》

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/72806.html

相關(guān)文章

  • 結(jié)合kmp算法匹配動畫淺析其基本思想

    摘要:寫在最前本次分享一下通過實(shí)現(xiàn)算法的動畫效果來試圖展示的基本思路。算法的關(guān)鍵是利用匹配失敗后的信息,盡量減少模式串與主串的匹配次數(shù)以達(dá)到快速匹配的目的。本次主要通過動畫演示的方式展現(xiàn)樸素算法與算法對比過程的異同從而試圖理解的基本思路。 寫在最前 本次分享一下通過實(shí)現(xiàn)kmp算法的動畫效果來試圖展示kmp的基本思路。 歡迎關(guān)注我的博客,不定期更新中—— 前置概念 字符串匹配 字符串匹配是計(jì)算...

    wpw 評論0 收藏0
  • 數(shù)據(jù)結(jié)構(gòu)-BF算法KMP算法

    摘要:算法代碼復(fù)雜度最壞情況的時間復(fù)雜度。算法簡單記憶分為兩步模式串掃描,生成數(shù)組,。算法對算法的回溯問題進(jìn)行了改進(jìn),在整個匹配過程中對主串僅需從頭至尾掃描一遍。在定義函數(shù)時在參數(shù)前加上改為引傳遞。一般情況為值傳遞,對象除外。 BF算法 代碼 復(fù)雜度 最壞情況的時間復(fù)雜度O(m*n)。m為模式串長度。n為目標(biāo)串長度。 KMP算法 代碼 時間復(fù)雜度 時間復(fù)雜度為O(m+n)。m為模式串長度...

    jollywing 評論0 收藏0
  • KMP模式匹配算法(一)從暴力匹配切入

    摘要:樸素的模式匹配算法這種算法又被稱為暴力匹配算法。如果匹配失敗,則回溯到主串的下一個位置重新逐位匹配。當(dāng)然,在匹配算法中不同的輸入會有不同的復(fù)雜度,最好的情況就是一開始就匹配成功。切入結(jié)束,下篇詳解匹配算法 最近在看關(guān)于算法方面的,正好看到關(guān)于KMP算法相關(guān)的部分,這里就做一個總結(jié)。假設(shè)我們有這樣的一個主串 S = googlgomglegoogle 和一個子串 C = google 我...

    xfee 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<