作用
给一个主串、一个子串,判断子串在主串中出现的位置,没有匹配则返回-1.
示例
主串:BBCABCDABABCDABCDABDE
子串:ABCDABD
输出:13
next数组手动求的话不需要用下面代码中那么高级的求法,杀鸡何用牛刀
子串字符 | A | B | C | D | A | B | D |
---|---|---|---|---|---|---|---|
下标x | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
next [x] | -1 | 0 | 0 | 0 | 0 | 1 | 2 |
代码
package 字符串;
public class 模式匹配 {
public static void main(String[] args) {
new 模式匹配().exe();
}
private void exe() {
int r1 = simple_index2("BBCABCDABABCDABCDABDE", "ABCDABD");
System.out.println("simple_index_result="+r1);
int r2 = kmp_index("BBCABCDABABCDABCDABDE", "ABCDABD");
System.out.println("kmp_index_result="+r2);
}
/**
* 简单模式匹配
* 子串在主串中开始出现的位置可能是[0,n-1],简单模式匹配就是对每个位置逐个判断
* @param str
* @param subStr
* @return
*/
private int simple_index(String str, String subStr) {
// i:指示器,指示主串中位置
// j:指示器,指示子串中的位置
int i = 0, j = 0;
while (i < str.length() && j < subStr.length()) {
if (str.charAt(i) == subStr.charAt(j)) {
i++;
j++;
} else {
i = i - j + 1;
j = 0;
}
}
if (j == subStr.length()) {
return i - j;
} else {
return -1;
}
}
private int simple_index2(String str, String subStr) {
int i = 0, j = 0;
// 标记str与substr本趟匹配开始的位置
int k = 0;
// 模式串在主串中的开始的位置可能是[0,str.length()-1],逐个进行判断
while (i < str.length() && j < subStr.length()) {
if (str.charAt(i) == subStr.charAt(j)) {
i++;
j++;
} else {
// i = i - j + 1;
i = ++k;
j = 0;
}
}
if (j == subStr.length()) {
// return i - j;
return k;
} else {
return -1;
}
}
/**
* 目的:保持i不动,通过调整j来消除i处的不匹配
*
* @param str
* @param subStr
* @return
*/
private int kmp_index(String str, String subStr) {
// next数组
int[] next = getNext(subStr);
// 主串
char[] strArr = str.toCharArray();
// 子串
char[] subStrArr = subStr.toCharArray();
int i = 0, j = 0;
while (i < str.length() && j < subStr.length()) {
if (strArr[i] == subStrArr[j]) {
// 该位相等
i++;
j++;
} else {
// 不等:kmp的目标是i不动,通过调整j使得调整能够继续
j = next[j];
// 但是next数组中标记了一种特殊情况:那就是当next[x]=-1时表示此时应该:i++;j=0
if (j == -1) {
i++;
j = 0;
}
}
}
if (j == subStr.length()) {
// 说明子串在主串中
return i - subStr.length();
}
return -1;
}
/**
* 得到next数组
*
* @param subStr
* @return
*/
private int[] getNext(String subStr) {
int n=subStr.length();
int[] next = new int[n];
next[0] = -1;
char[] subStrArr = subStr.toCharArray();
int i = 0, j = -1;
while (i < n-1) {// 这里要i<n-1,一开始写的i<n导致最后数组越界了
if ( (j == -1) || (subStrArr[i] == subStrArr[j]) ) {
// j==-1时:从数组中取元素都要越界了,还不赶紧前进一位!!
i++;
j++;
next[i] = j;
} else {
j = next[j];
}
}
return next;
}
}
网友评论