002字符串查找---KMP算法
本文参考《算法(第4版)》
1.暴力字符串查找算法
子字符串查找的最显而易见的方法就是在文本模式中任何可能发生匹配的地方检查匹配是否存在。
暴力字符串查找算法是一种子字符串查找算法,是模式字符串在文本字符串中逐个字符进行比较。
search()方式使用一个指针 i 跟踪文本字符串,使用一个指针 j 跟踪跟踪模式字符串。
假定从左到右方向比较字符串,文本指针和模式指针起始比较位置都为0,当文本字符和模式字符匹配时,则模式指针向右移动一位,继续和文本字符串的下一位进行比较。
匹配失败时,文本指针 i 右移一位,同时模式指针 j 回退到模式字符串的起始位置,再进行下一轮比较,直到找到一个不匹配的字符或者模式结束于j == M。
该方法中发生模式不匹配时,文本指标和模式指针都需要回退。由于绝大时候不匹配发生在第一个字符,所以模式指针 j 的增长机会很少,算法的时间复杂度和文本字符串长度N成正比。
在最坏的情况下暴力字符串查找算法在长度为N的文本字符串中查找长度为M的模式字符串所需要的比较次数和NM成正比。
search2()方法是暴力字符串查找算法的另一种实现。
实现代码:
package subStringSearch;
public class ForceSearch {
public static int search(String pat, String txt){
int M = pat.length();
int N = txt.length();
for(int i = 0; i <= N - M; i++){
int j;
for(j = 0; j < M; j++)
if(pat.charAt(j)!=txt.charAt(i+j))
break;
if(j == M) return i;
}
return N;
}
public static int search2(String pat, String txt){
int M = pat.length();
int N = txt.length();
int j = 0;
for(int i = 0; i < N; i++){
if(pat.charAt(j) == txt.charAt(j)) j++;
else{ i -= j; j = 0;}
if(j == M) return i - M;
}
return N;
}
public static void main(String[] args) {
String pat = "abcd";
String txt = "adsedsabcdeabcdf";
int index = search(pat, txt);
System.out.println(index);
System.out.println(txt.substring(index, index+pat.length()));
int index2 = search(pat, txt);
System.out.println(index2);
System.out.println(txt.substring(index, index2+pat.length()));
}
}
输出:
6
abcd
6
abcd
2.KMP算法
package subStringSearch;
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 = "abcd";
String txt = "adsedsabcdeabcdf";
KMP kmp = new KMP(pat);
int index = kmp.search(txt);
System.out.println(index);
System.out.println(txt.substring(index, index+pat.length()));
}
}
输出:
6
abcd