KMP子字符串查找算法

KMP算法解决的问题是,在暴力匹配时文本指针不需要回退。基本思想就是当出现不匹配时,就能知晓一部分文本的内容(因为在匹配失败之前它们已经和模式相匹配)。我们可以利用这些信息避免将指针回退到所有这些已知的字符之前。

正文——A B A A A A B A A A A A A A A
模式——B A A A A A
模式—— B A A A A A
模式—— B A A A A A
模式—— B A A A A A
模式—— B A A A A A
模式—— B A A A A A
模式—— B A A A A A

如果是暴力匹配的话,指针需要移动6次,但是可以看出其实不需要移动这么多次。
正文——A B A A A A B A A A A A A A A
模式—— B A A A A A
模式—— B A A A A A

提前判断如何重新开始查找,而这种判断只取决于模式本身。我们通过确定有限状态自动机(DFA)。模式中的每个字符都对应着一个状态,每个此类状态都能转换为字母表中的任意字符。

和模式字符串ABABAC对应的确定有限状态自动机
package chapter5;

/**
 * Created by Blue on 2017/9/4.
 */
public class KMP {
    private String pat;
    private int[][] dfa;

    public KMP(String pat) {
        this.pat = pat;
        int M = pat.length();
        int R = 256;
        dfa = new int[R][M];
        dfa[pat.charAt(0)][0] = 1;
        for (int X = 0, j = 1; j < M; j++) {
            for (int c = 0; c < R; c++) {
                dfa[c][j] = dfa[c][X];
            }
            dfa[pat.charAt(j)][j] = j + 1;
            X = dfa[pat.charAt(j)][X];
        }  
    }

    public int search(String txt) {
        int i, j, N = txt.length(), M = pat.length();
        for (i = 0, j = 0; i < N && j < M; i++)
            j = dfa[txt.charAt(i)][j];
        if (j == M) return i - M;
        else return N;
    }

    public static void main(String[] args) {
        String pat = "ABABAC";
        String txt = "BCBAABACAABABACAA";
        KMP kmp = new KMP(pat);
        System.out.println(txt);
        int offset = kmp.search(txt);
        for (int i = 0; i < offset; i++)
            System.out.print(" ");
        System.out.println(pat);
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容