KMP匹配算法
1.简介
简单匹配算法虽然易于实现,但是时间复杂度比较高。Knuth、Morris和Pratt发明了快速字符串匹配算法,算法以这三个人的名字命名,即KMP算法。
KMP算法的想法是,设法利用这个已知信息,不要把"搜索位置"移回已经比较过的位置,继续把它向后移,这样就提高了效率。
2.match表
[1].举例:
字符串: bread
前缀:b,br,bre,brea
后缀:read,ead,ad,d
生成方式:
match[0] = -1;
从i = 1遍历数组到i = pattern.length - 1
每次遍历记录j = match[i-1]
让j = match[j],此处使用while循环,循环条件是j >= 0 && 字符 i != j+1
如果字符i == j+1,match[i] = ++j;
如果i != j ,match[i] = -1
匹配方式:
主串指针i,子串指针j
while(指针i和指针j没有越界)
如果指针i和指针j对应字符相等,i++,j++;
不相等时,如果指针j不在0的位置,j = match[j - 1] + 1
否则指针i后移
循环结束后,如果指针j == 子串长度,表示找到了子串
返回i - 子串长度,否则返回-1
public class KMP {
/**
* match数组
*/
private int [] match;
/**
* 主串
*/
private String mainStr;
/**
* 子串
*/
private String subStr;
/**
* 构造器
* @param mainStr 主串
* @param subStr 子串
*/
public KMP(String mainStr,String subStr) {
try {
this.subStr = subStr;
this.mainStr = mainStr;
match = new int[subStr.length()];
initMatch();//初始化match表
}
catch (Exception e) {
// TODO: handle exception
System.out.println("字符串非法!!!");
System.exit(0);//终止运行
}
}
/**
* 初始化match表中的值
*/
public void initMatch() {
int len = subStr.length();
match[0] = -1;
for(int i = 1; i < len; i++) {
//获得当前位置的前一个字符的部分匹配值
int j = match[i - 1];
while(j >= 0 && subStr.charAt(i) != subStr.charAt(j+1)) {
j = match[j];
}
if(subStr.charAt(i) == subStr.charAt(j+1)) {
match[i] = j + 1;
}
else {
match[i] = -1;
}
}
}
/**
* 匹配字符串,找到子串,返回子串出现的位置
* 否则返回-1
* @return
*/
public int getMatchResult() {
try {
int mainLength = mainStr.length();
int subLength = subStr.length();
//如果主串长度小于子串长度,不可能匹配到
if(mainLength < subLength) {
return -1;
}
int i = 0;//主串指针
int j = 0;//子串指针
while(i < mainLength && j < subLength) {
if(mainStr.charAt(i) == subStr.charAt(j)) {
i++;
j++;
}
else if(j != 0) {
j = match[j - 1] + 1;
}
else {
i++;
}
}
return (j == subLength) ? i - subLength : -1;
}
//如果捕捉到异常,参与比较的两个字符串不合法
catch (Exception e) {
System.out.println("参与比较的字符串非法!!!");
}
return -1;
}
/**
* 在主串中找到子串出现的所有位置,找到返回位置数组
* 否则返回null
* @return
*/
public int [] getMatchValueArray() {
try {
int mainLength = mainStr.length();
int subLength = subStr.length();
//如果主串长度小于子串长度,不可能匹配到
if(mainLength < subLength) {
return null;
}
int i = 0;//主串指针
int j = 0;//子串指针
while(i < mainLength && j < subLength) {
if(mainStr.charAt(i) == subStr.charAt(j)) {
i++;
j++;
}
else if(j != 0) {
j = match[j - 1] + 1;
}
else {
i++;
}
}
}
//如果捕捉到异常,参与比较的两个字符串不合法
catch (Exception e) {
System.out.println("参与比较的字符串非法!!!");
}
return null;
}
public int[] getMatch() {
return match;
}
public void setMatch(int[] match) {
this.match = match;
}
public String getMainStr() {
return mainStr;
}
public void setMainStr(String mainStr) {
this.mainStr = mainStr;
}
public String getSubStr() {
return subStr;
}
public void setSubStr(String subStr) {
this.subStr = subStr;
}
}
public void setMainStr(String mainStr) {
this.mainStr = mainStr;
}
public String getSubStr() {
return subStr;
}
public void setSubStr(String subStr) {
this.subStr = subStr;
}
}