求一个字符串(模式串)在另一个字符串(主串)中的位置,称为字符串模式匹配。
朴素字符串模式匹配
- 在朴素的字符串模式匹配算法中,对主串S和模式串T分别设置指针i和j,假设字符串下标从0开始,初始时i和j分别指向每个串的第0个位置。在第n趟匹配开始时,i指向主串S中的第n-1个位置,j指向模式串T的第0个位置,然后逐个向后比较。若T中的每一个字符都与S中的字符相等,则称匹配成功;否则,当遇到某个字符不相等时,i重新指向S的第n个位置,j重新指向T的第0个位置,继续进行第n+1趟匹配。
KMP
-
利用已经得到的部分匹配,使模式串尽可能多的向右滑动一段距离。
-
利用
next
数组,存部分匹配值( 模式串前后缀的最长共有元素长度 )例如:ABCDABD的next数组为: 以当前位置为结尾的模式串的前后缀的公共部分
”A”的前缀和后缀都为空集,共有元素的长度为0;
”AB”的前缀为[A],后缀为[B],共有元素的长度为0;
”ABC”的前缀为[A, AB],后缀为[BC, C],共有元素的长度0;
”ABCD”的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为0;
”ABCDA”的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为”A”,长度为1;
”ABCDAB”的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为”AB”,长度为2;
”ABCDABD”的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB],后缀为[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的长度为0。 -
那么在不匹配的位置时,查找匹配失败的位置的前一个位置的next值,然后
已经匹配成功的位数-next值
,得到向右移动的位数。 -
例如:Str1 = “BBC ABCDAB ABCDABCDABDE”,Str2 = “ABCDABD”
在D匹配失败,则查找B的next=2。已经匹配成功的ABCDAB=6,则向右移动6-2=4位: -
Java实现:
public class KMP {
public static void main(String[] args) {
System.out.println(kmp("abcabaabaabcacb", "abaabcac"));
}
//next数组
public static int[] getNext(char[] t) {
int[] next = new int[t.length];
next[0] = -1;
next[1] = 0;
int k;
for (int j = 2; j < t.length; j++) {
k=next[j-1];
while (k!=-1) {
if (t[j-1] == t[k]) {
next[j] = k + 1;
break;
}
else {
k = next[k];
next[j] = 0;
}
}
}
return next;
}
//若匹配成功,返回t在s中的位置(第一个相同字符对应的位置),否则返回-1
public static int kmp(String s, String t){
char[] sarr = s.toCharArray();
char[] tarr = t.toCharArray();
int[] next = getNext(tarr);
int i = 0, j = 0;
while (i<sarr.length && j<tarr.length){
if(j == -1 || s_arr[i]==tarr[j]){
i++;
j++;
}
else
j = next[j];
}
if(j == tarr.length)
return i-j;
else
return -1;
}
}
【参考文档】
KMP算法详解及其Java实现
KMP算法详解与Java实现