字符串匹配算法
给定两个串,查找一个串是否在另一个串里面(m代表主串长度,n代表子串长度),总共有两中算法,分别如下:
BF算法
又称为朴素算法(暴力算法),时间复杂度为O(n*m)
算法思想:
从原字符串str的pos(i)位置出发,与目标字符串sub(j)的第一位进行匹配,若相等,接着匹配后一位字符,若不相等,则返回到str的前一次匹配位置的后一位,接着与sub的起始位进行匹配,直到与sub全部匹配成功,则返回在str中开始完全匹配的下标。
简单说这个算法的思想就是匹配失败,原字符串就重新从上一次匹配位置的下一位开始匹配,而目标字符串就又重新开始。
BF算法具体代码实现:
public static int BF(String str,String sub,int pos) {
int lenstr = str.length();
int lensub = sub.length();
//判断pos位置的合法性
if(pos < 0 || pos > lenstr){
return -1;
//或者throw new UnsupportedOperationException("pos位置不合法");
}
int i = pos;
int j = 0;
while (i < lenstr && j < lensub){//说明没有遍历完
if(str.charAt(i) == sub.charAt(j)){//当数据相等时
i++;
j++;
}else{//当数据不等时
i = i-j+1;
j = 0;
}
}
if(j >= lensub){//遍历完找到了子字符串
return i-j;///返回下标
}else {
return -1;//没有找到
}
}
KMP算法
是在BF算法的基础上,减少了时间复杂度,为O(n+m)
KMP 和 BF 唯一不一样的地方在于,主串的 i 并不会回退,并且 j 也不会都退回到 0号位置,而是退回到一个特定的位置。因此增加了一个数组next[],用来存放子串下标j在匹配失败时的返回位置。
注意: next数组是在目标字符串上的,与原字符串无关。
手动得到next数组的方法:
KMP算法next数组的优化得到nextval数组:
Next数组具体代码实现:
public static void getNext(String sub, int next[]) {//得到next数组的值
next[0] = -1;
next[1] = 0;
int j = 2;//下一项要求的j的值,第二项
int k = 0;//前一项的next值
while (j < sub.length()){///没有遍历完
if (k == -1|| sub.charAt(k) == sub.charAt(j-1)){//j-1代表前一项
next[j] = k+1;//next[j]= -1+1=0
j ++;
k = k+1;
}else {
k = next[k];
}
}
}
为何要修正优化next数组?
可以在类似于aaaaaaab这种字符串中快速退回到指定的下标处从而节约时间。如下图:
KMP算法具体代码实现:
public static int KMP(String str,String sub,int pos) {
int i = pos;
int j = 0;
int lenstr = str.length();
int lensub = sub.length();
int next[] = new int[lensub];//定义一个next数组,用来存放j所要返回的下标;
getNext(sub, next);//调用getNext函数
while (i < lenstr && j < lensub) {//说明没有遍历完
if (j == -1||str.charAt(i) == sub.charAt(j)) {
i++;
j++;
} else {
j = next[j];//j退回到next数组存储值所表示的位置处
}
}
if (j >= lensub) {
return i-j;
} else {
return -1;
}
}
(欢迎讨论指正!)