【左神算法】 KMP算法

1.思路

字符串匹配,通常我們使用的是互相比較,也就是 str1 : ABCABCD st2 : ABCABCT
str1 和 str2按照順序比較。當匹配到str1的D 和 str2的T位置可以發現,不等。則直接從str1的第一個A+1位置在匹配。可以發現這樣就是窮舉的方法,相對來說是一種時間複雜度比較高的。因此,就出現了KMP算法。

KMP字符串匹配算法: KMP的核心思想是先計算出當前字符的最長前綴和最長後綴的最長長度。不包含第一個前綴和最後一個後綴。
舉一個栗子,ABCABCD D的最長子串是多少 爲ABC ABC 爲3,而AAAAD D的最長子串長度爲3 不能包含第一個A和最後一個A。而在計算KMP算法之前需要先計算出最長子串的長度。ababac 的最長子串的長度分別爲 [-1,0,0,1,2,3]。
基於最長子串長度這個數組,就可以實現KMP算法。還是計算str1: abkababkabd str2:abkababkabf 當str1移動到d位置 str2移動到f位置,發現不相等。而我們之前的做法是將str1的指針移動到開頭a+1的位置,也就是b的位置從先計算。但是KMP算法基於之前計算的最長子串數組,可以有一個很大的改進,那就是不需要從a+1的位置開始。
ps:重點來了。會取出str2中f的前一個位置最長子串數組的長度。爲5(最長串爲 abkab)從str1的a+5位置比較。這樣就避免了a+1 一個位置一個位置的重複比較。爲什麼這樣比較呢。因爲在str1中的第一個最長子串abkab已經比較過了。不存在相同的,所以直接從a+5的位置比較。
那麼在str1 a到a+5位置開始的位置到最終str1末尾的位置會不會存在一個和str2想匹配的字符串呢。
我們假設存在一個上述的條件,在已知str2最長子串中,如果存在一個那麼勢必就是str1的最長後綴子串,所以第一個條件是不存在的。
好了,上面就是kmp算法的核心。
接下來,我們來梳理一下KMP算法的流程。
getNextArray();首先需要初始化0 1 位置的參數,pos的表示當前位置大小。而cn表示當前位置的之前的最長子串的長度爲多少。如果當前位置的前一個位置str2[pos-1]和str2[cn] 也就是最大子串的長度的位置元素相等。當前pos的cn++.

2.code

package com.ncst.improve.one;

/**
 * @author i
 * @create 2020/6/30 17:04
 * @Description
 */
public class KMP {

    public static int kmp(String str1,String str2){
        if (str1 == null || str2 == null || str1.length()<str2.length() || str2.length() < 1){
            return -1;
        }
        char [] ch1 = str1.toCharArray();
        char [] ch2 = str2.toCharArray();
        int c1 = 0;
        int c2 = 0;
        int [] next = getNextArray(ch2);
        while (c1<ch1.length && c2<ch2.length){
            if (ch1[c1] == ch2[c2]){
                c1++;
                c2++;
            }else if (next[c2] == -1){
                c1++;
            }else {
                c2 = next[c2];
            }
        }
        return c2 == ch2.length ? c1-c2 : -1;
    }

    public static int [] getNextArray(char [] str2){
        if (str2.length == 1){
            return new int [-1];
        }
        int [] next = new int [str2.length];
        next[0] = -1;
        next[1] = 0;
        int pos = 2;//走到那個位置
        int cn = 0;//當前位置的最長子串個數
        while (pos<next.length){
            if (str2[pos-1] == str2[cn]){
                next[pos++] = ++cn;
            }else if (cn>0){
                cn = next[cn];
            }else {
                next[pos++] = 0;
            }
        }
        return next;
    }

    public static void main(String[] args) {
        String str = "abdabc";
        String str2 = "abc";
        System.out.println(kmp(str, str2));
    }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章