1. 程式人生 > >kpm字符串匹配算法

kpm字符串匹配算法

字符 前綴 返回 bsp src 簡單的 發現 匹配算法 spa

首先是簡單的樸素匹配算法

    /*
     * 返回子串t在主串s的位置,若不存在則返回0
     */
    public static int index(String s, String t) {
        
        int i = 0;//i記錄主串當前位置的下標
        int j = 0;    //j記錄子串當前位置的下標
        
        char[] c = t.toCharArray();
        char[] d = s.toCharArray();
        while(i < s.length() && j < t.length()) {
            
if(c[i] == d[j]) { i++; j++; if(j == t.length()) { break; } }else { i = i - j;//如果不匹配i退回到上次匹配首位的下一位 j = 0; } } if(j == t.length()) { return
i - j + 1; } return 0; }

舉例說明:

技術分享

s是 abcabcabd t是 abcabd,樸素的匹配算法每次發現不對都要重新回到上次匹配的首位,也就是要重新在s從找一次t的和第一個字符匹配的字符。

但是像這個例子t字符串中一開始就有ab後面也有ab,也就是說如果匹配到最後一位發現不匹配的時候,就可以直接進行到這裏

技術分享

所以這就是kmp改進的地方,先自行處理一下t字符串,找到t字符串中與前綴有重復的。建立一個next數組記錄下這個重復,就比如這個t匹配到最後一個時發現s[5]和t[5]匹配失敗,但是t[3]t[4]和t[1]t[2]是重復的,所以這裏可以直接進行s[5]和t[3]的匹配。從代碼的角度講就是當i=5,j=5時,s[i]和t[j]匹配失敗,那就修改j跳過之前與t字符串前綴重復的。

技術分享

這是一個next數組,這裏j=0時沒有前綴所以在匹配的時候就應該重t[0]開始匹配,j=1時前綴是a但是t[1]是b所以沒有重復,所以還是0,一直到j=3,a和前綴a重復所以所以在匹配的時候就應該重t[1]開始匹配,到j=4,ab和前綴ab重復所以所以在匹配的時候就應該重t[2]開始匹配,j=5的時候abd和前綴abc並沒有重復所以應該重t[0]開始匹配。

再然後就是這個next數組怎麽計算。。

聲明一個k初始化為0用於記錄前綴被重復的長度了,就比如t[3]和t[0]重復就記1,此時next[]相應的位置就是1(k),t[3]t[4]和t[0]t[1]重復就記2,此時此時next[]相應的位置就是2(k),t[3]t[4]t[5]t[0]t[1]t[3不]重復就置0。

整體代碼:

public static int KmpIndex(String s, String t) {
        int i = 0;
        int j = 0;    //j記錄子串當前位置的下標
        int[] next = new int[t.length()];
        char[] c = t.toCharArray();
        char[] d = s.toCharArray();
        int k = 0;
        
        while(j < t.length()) {
            if(k == 0 && j == 0) {
                //第一個字符的前後綴為空
                next[j++] = 0;
            }else {
                //使用k來記住已經和前者匹配到那個位置了
                if(k == 0 ) {
                    //k=0 就是上一個未匹配
                    if(c[k] != c[j]) {
                        //不相等就是不匹配
                        next[j++] = 0;
                    }else {
                        //相等就是匹配,next[j]等於k+1,然後增加k和j的值
                        next[j++] = ++k;
                    }
                }else {
                    //k!=0 就是上k個都已經匹配了
                    if(c[k] != c[j]) {
                        //不相等就是不匹配而且之後要重頭匹配 k=0
                        next[j++] = 0;
                        k = 0;
                    }else {
                        //相等就是匹配,next[j]等於k+1,然後增加k和j的值
                        next[j++] = ++k;
                    }
                }
            }
        }
        j = 0;
        while(i < s.length() && j < t.length()) {
            if(d[i] == c[j]) {
                i++;
                j++;
                if(j == t.length()) {
                    break;
                }
            }else {
                j = next[j];
            }
        }
        if(j == t.length()) {
            return i - j;
        }
        return 0;
    }

kpm字符串匹配算法