BF算法,即暴力(Brute Force)算法,是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和 T的第二个字符;若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的匹配结果。BF算法是一种蛮力算法。
KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n) [1] 。
subI都置为0
,从头测试,
subI
都没有达到子字符串的长度,那么就返回-1
【即不存在】,返回 i - subI
public static int BFMatch(String str, String subStr) {
//预防一些奇葩事例
if(str == null || subStr == null ||
str.length() == 0 || subStr.length() == 0) {
return -1;
}
int i = 0;
int subI = 0;
while(i < str.length() && subI < subStr.length()) {
//相同一起走一步
if(str.charAt(i) == subStr.charAt(subI)) {
i++;
subI++;
}else {
//i要回退
i = i - subI + 1;
//subI要回退为初始位置0
subI = 0;
}
}
return subI == subStr.length() ? i - subI : -1;
}
public static void main(String[] args) {
System.out.println(BFMatch("mississippi", "issip"));
}
subI
都直接清0,但是实际上,应该是有一部分还可以保留
没错,subI
并没有直接清为0,而是找到了前面可以用的一部分,继续走,而【i】,从始至终都从未回退!
要实现这个算法,很重要的一个点就是,subI
回退到哪?
next
数组来记录subStr
的每一个停下的话要回退到哪。length()
—>提高效率charAt()
—> 提高效率next
数组
getNext(next, subStrArr, subLen);
subI = next[subI];
===》subI
的回退public static int strStr(String str, String subStr) {
//1.***********************
if(str == null || subStr == null ||
str.length() == 0 || subStr.length() == 0) {
return -1;
}
//2.***********************
int i = 0;
int subI = 0;
//3.***********************
int strLen = str.length();
int subLen = subStr.length();
//4.***********************
char[] strArr = str.toCharArray();
char[] subStrArr = subStr.toCharArray();
//5.***********************
int[] next = new int[subLen];
next[0] = -1;
if(subLen != 1) {
getNext(next, subStrArr, subLen);
}
//6.***********************
while(i < strLen && subI < subLen) {
if(subI == -1 || strArr[i] == subStrArr[subI]) {
i++;
subI++;
}else {
subI = next[subI];
}
}
return subI == subLen ? i - subI : -1;
}
理论基础:
那么 k 对应的值就是前面重复部分的长度【三种值, -1 , 0 , > 0】【-1, 就是首元素的回退,当然使用的时候要判断一下,避免数组越界访问】
接下来我们要来看看如何求具体某一个下标对应的next值
假设,我说假设!
next[X - 1]
,next[X]
可以求吗?如上图,要求next[X]
,知道next[X - 1]
,怎么求 next[X] 呢?
Ⅰ.如果 k == next[x - 1]
,满足 subStr.charAt( k ) == subStr.charAt(X - 1)
有如下关系(伪代码)
【0, k -1】 + 【k - 1, k】 == 【i - k, i - 1】 + 【i - 1, i】;
也就是
【0, k】 == 【i - k, i】;
所以next[X] = k + 1
Ⅱ. 如果不相等,则说明 “不能-少-回退那么多”,要 “多回退一点”
int[] next = new int[subLen];
next[0] = -1;
if(subLen != 1) { //只有一个字符就不需要这个方法了
getNext(next, subStrArr, subLen);
}
public static void getNext(int[] next, char[] arr, int len) {
//白手起家
int k = 0;
//白手起家所需要的原材料,把值能确定的先赋值上
//这种【递推思想】的题,有原材料做起来会更好,好比珍珠成型之前也需要一颗小石子
next[1] = 0;
int i = 2;
//遍历每一位
while(i < len) {
//相等或者无法再次回退
if(k == -1 || arr[i - 1] == arr[k]) {
next[i] = k + 1;
i++;
k++;//k变长
}else {
k = next[k];//k变短
}
}
}
还记不记得这张图?
接下来我们设计一个方法getNextValue()
,去修改一些next值,避免上面的状况
public static int[] getNextValue(int[] next, int len, char[] arr) {
int[] nextValue = new int[len];
nextValue[0] = -1;
//遍历整个数组
for (int i = 1; i < len; i++) {
int n = next[i];
if(arr[i] == arr[n]) {
nextValue[i] = nextValue[n];
}else {
nextValue[i] = n;
}
}
return nextValue;
}
if(arr[i] == arr[n]) {
nextValue[i] = nextValue[n];
}
else {
nextValue[i] = n;
}
//在strStr()方法,匹配前,补充上如下代码,并之后使用next的都改成使用nextValue;
int[] nextValue = getNextValue(next, subLen, subStrArr);
文章到此结束!谢谢观看
可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭!这是我的代码仓库!(在马拉圈的23.2里)代码仓库
字符串匹配算法 · 具体位置
邮箱:[email protected]