import java.util.Arrays;
/**
* @program: sorttest
* @description: KMP算法
* @author: zhaozhenwei
* @create: 2021-03-28 18:44
**/
public class KMPAlgorithm {
public static void main(String[] args) {
String mainStr = "123124128903124124124567890378";
String subStr = "124124124";
int[] nextVal = nextVal(subStr);
System.out.println(Arrays.toString(nextVal));
int startIndex = containers1(mainStr, subStr);
System.out.println(startIndex);
startIndex = containers2(mainStr, subStr);
System.out.println(startIndex);
}
/**
* 校验mainString中是否包含subString
* @param mainString 主串
* @param subString 字串
* @return
*/
public static int containers(String mainString, String subString) {
// 主串、子串为空的时候返回false,表示不包含
if (null == mainString || null == subString) {
return -1;
}
return containers2(mainString, subString);
}
/**
* KMP算法
* **目前只知道改怎么做,具体原理暂时无法说清**
* 1、计算子串中每个下标前的集合中最大的相同的前缀和后缀的长度,放在临时数组中nextVal,该数组用于表示下次比较时从子串的那个下标开始比较
* 2、对主串和字串进行比较,假如比较到主串下标A,子串下标B时,字符不一致时,停止比较,
* 3、根据当前子串的下标B通过nextVal获取当前应当从子串的那个下标处开始比较
* 4、主串则从之前元素不同的地方A进行比较,如果之前是主串和字串比较的第一个元素不同而停止比较的,则需要将A向后移一位,和字串的下标0进行比较
* @param mainString
* @param subString
* @return
*/
private static int containers2(String mainString, String subString) {
int mainStrLength = mainString.length();
int subStrLength = subString.length();
if (mainStrLength < subStrLength) {
return -1;
}
int[] nextVal = nextVal(subString);
int subStartIndex = 0;
for (int i = 0; i < mainStrLength - subStrLength; ) {
for (; subStartIndex < subStrLength; subStartIndex++) {
if (mainString.charAt(i) == subString.charAt(subStartIndex)) {
i++;
} else {
break;
}
}
// 当主串当前比较的第一个元素和子串第一个元素不相等时,将主串的位置向后移一位
if (subStartIndex == 0) {
i++;
}
if (subStartIndex < subStrLength) {
subStartIndex = nextVal[subStartIndex];
} else {
return i - subStrLength;
}
}
return -1;
}
/**
* 查找字符串str中每个下标前的子串A中最长的前缀和后缀相等的字符长度
* 要找的前缀和后缀的长度需要小于子串A的长度
* @param str
* @return
*/
private static int[] nextVal(String str) {
int strLen = str.length();
int[] nextValArr = new int[strLen];
for (int i = 1; i < strLen; i++) {
int start = 0;
int end = i - 1;
for (int j = 0; j < end; j++) {
for (int k = 0; k < j; k++) {
String prefix = str.substring(start, start+k+1);
String suffix = str.substring(end - k, end+1);
if (prefix.equals(suffix)) {
nextValArr[i] = k+1;
}
}
}
}
return nextValArr;
}
/**
* 暴力方法
* 通过对主串的下标依次增加,对主串的每个子串进行比较
* @param mainString
* @param subString
* @return
*/
private static int containers1(String mainString, String subString) {
int mainStrLength = mainString.length();
int subStrLength = subString.length();
if (mainStrLength < subStrLength) {
return -1;
}
// 从主串的第一个元素开始,截取和子串相同长度的子串进行比较
// 从下标0为开始,比较截取的子串和要比较的字串
// 相同的话下标各子加1,继续比较
// 不同的时候,从主串的下一个下标截取子串,再次和传进来的子串进行比较
for (int i = 0; i <= mainStrLength - subStrLength; i++) {
int k = i;
int l = 0;
for (int j = 0; j < subStrLength; j++) {
if (mainString.charAt(k) == subString.charAt(j)) {
k++;
l++;
} else {
break;
}
}
// 跳出循环时,如果比较的长度和要比较的子串的长度一致时,说明主串包含子串
if (l == subStrLength) {
return k - subStrLength;
}
}
return -1;
}
}
KMP
最新推荐文章于 2024-03-24 17:35:43 发布