算法思想引入
字符串匹配很好理解他就是在一个给定的字符串(sourceString)中找是否包含有我们要找的字符串(targetString),最简单的就是我们的暴力匹配我们用最笨的办法一个一个一步一步的去比较去匹配,这样的话在最坏的情况下我们需要执行的时间复杂度就是m*n,m,n分别代表的是我们给定字符串的长度以及目标字符串的长度。
暴力匹配算法代码实现:
public static int boLiSearch(String sourceStrings, String targetStrings) {
char[] sourceCharArrays = sourceStrings.toCharArray();
char[] targetCharArrays = targetStrings.toCharArray();
int targetLocation = -1;
int sCount = sourceCharArrays.length;
int tCount = targetCharArrays.length;
int flag = sourceCharArrays.length - targetCharArrays.length;
int s = 0;
int t = 0;
while (s<sCount&&t<tCount) {
if (!(sourceCharArrays[s] == targetCharArrays[t])) {
s = s - t + 1;
t = 0;
}else{
s++;
t++;
}
if (t == tCount) {
targetLocation = s-t;
break;
}
}
System.out.println("boli start index = "+targetLocation);
return targetLocation;
}
KMP算法思想介绍
这是最笨的方法,我们也容易观察到他的妹子匹配都是从sourceString的下标仅仅只走一个index,targetString匹配的位置都也是从头开始,这样明显有些比较在原来的比较中是已经比较过的,不需要再次比较的,不需要比较的这些有什么样的规律,我们又应该如何避免呢?这就是我们KMP算法所需要的解决的问题,但是老实说KMP算法真的不好说,也不好理解。接下来我就尝试着自圆其说吧,欧力给!!!
KMP算法的第一步就是要求出next数组,next数组的实现思想相对于来说是简单的,他主要是用了最长前缀与最长后缀的概念:
这一部分的内容是摘抄尚硅谷韩顺平老师的算法讲义,想要系统学算法的同学可以去B站学习这个老师的视频教程,感觉这个老师讲的韩式很好的。
接下来主要要说明的是我们的匹配的过程中为什么可以通过这个next数组来实现我们的多步移动?
如果想要很好的理解这个跳转问题以及sourceFlag的跳转问题我们应该将自己的焦点聚焦于targetString中已经比较过的那段字符而不是targetString的全部长度的字符。
在我们暴力算法中我们在新一次的比较中targetString应该是从0开始的,但是由于现在next数组的存在,我们知道在已经比较过的那段字符中有一段我们是可以跳过的,但是这个跳过应该是在
KMP算法代码分析
next数组求解,核心代码分析:
KMP算法代码实现
public static int kmpSearch(String sourceStrings, String targetStrings) {
//对数据做一个初始化的处理
char[] sourceChars = sourceStrings.toCharArray();
char[] targetChars = targetStrings.toCharArray();
//对连个数据设置一个对比的游标
int sourceFlag =0;
int targetFlag = 0;
//sourceChars中每个字符对应的跳跃数
int[] next = jumpValues(targetStrings);
//记录对比过程中走过的路长
int stepNumber = 0;
while (sourceFlag<sourceChars.length&&targetFlag<targetChars.length){
if (sourceChars[sourceFlag]!=targetChars[targetFlag]){
int start = (sourceFlag-stepNumber);
int skip = ((stepNumber-next[(targetFlag==0?0:targetFlag-1)])==0?1:(stepNumber-next[(targetFlag==0?0:targetFlag-1)]));
targetFlag = next[(targetFlag==0?0:targetFlag-1)];
sourceFlag =start+skip ;
stepNumber = targetFlag;
}else{
stepNumber ++;
targetFlag ++;
sourceFlag ++;
}
if (stepNumber==targetChars.length){
System.out.println("kmp start index = "+(sourceFlag-stepNumber));
return sourceFlag-stepNumber;
}
}
return -1;
}
public static int[] jumpValues(String targetStrings){
char[] charArrays = targetStrings.toCharArray();
int[] jumpValueArrays = new int[charArrays.length];
// int tempValue = 0;
//只有当字符串中的字符不少于一个字符的时候我们的字符串采用前缀后缀之说
//提取出字符的个数,提高算法的效率
int charArraysCount = charArrays.length;
//控制目标字符的长度
for (int i = 1; i < charArraysCount; i++) {
//求当前目标字符的跳跃长度,逐一探索
// int skipValue = 0;
for(int j = 0;j<i;j++){
int flagLeft = 0;
int flagRight = i-j;
while (flagLeft<=j){
if (charArrays[flagLeft]==charArrays[flagRight]){
flagLeft++;
flagRight++;
}else{
break;
}
}
if((flagLeft-1)==j){
jumpValueArrays[i] = j+1;
}
}
}
System.out.println("next arrays :"+Arrays.toString(jumpValueArrays));
return jumpValueArrays;
}