KMP算法,字符串搜索

相比于暴力方法,KMP算法进行字符串搜索时可以根据子串自己的特性,以确定当前是否匹配成功。简单来讲,就是使用了子串的每个字符的集合作为一个状态,创建一个有限状态机(DFA)。
比如要查找的子串为 ABABAC,那么对于每个位置的状态只有三个,即A、B、C,所以可以建立如下表格:

j 0 1 2 3 4 5
A B A B A C
A 1 1 3 1 5 1
B 0 2 0 4 0 4
C 0 0 0 0 0 6

i 表示现在文本中的位置, j 表示子串的位置。上面的矩阵dfa[i][j] 即为子串第j个位置时,如果出现的字符为表的第i行对应的字符( A、B、C中的一个),那么它此时j应该跳转到的位置即为 dfa[i][j]。不管怎样, i 都只是增长而不回退。《算法》第四版的500页有清晰的图示,可以参考。下面的代码也是摘抄自此书。

package kmp;

import java.util.Scanner;

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) {
        Scanner scanner = new Scanner(System.in);
        String txt = scanner.nextLine();
        String pat = scanner.nextLine();
        scanner.close();
        KMP kmp = new KMP(pat);
        System.out.print("text:    ");
        System.out.println(txt);
        int offset = kmp.search(txt);
        System.out.print("pattern: ");
        for(int i = 0; i < offset; ++i)
            System.out.print(" ");
        System.out.println(pat);
    }
}

你可能感兴趣的:(算法)