package com.example.test_utils.algorithm;
/**
* @author bao-fa
* @date 2021/10/15
* 字符串模式匹配,匹配成功,返回子串在主串中第一个字符的下标,匹配失败返回-1
* 暴力算法和kmp算法、kmp优化算法未完成
*/
public class FindIndex {
public static void main(String[] args) {
//构造较长的主串。
StringBuilder str = new StringBuilder();
for (double i = 0; i < 10000; i++) {
str.append('a');
}
String s = str.append('c').toString();
//构造较长的子串
StringBuilder tr = new StringBuilder();
for (double i = 0; i < 1000; i++) {
tr.append('a');
}
String t = tr.append('c').toString();
//测试两种算法的效率差异
//暴力匹配算法 输出程序执行时间,输出查找位置
long startTime = System.currentTimeMillis();
int indexByViolence = violenceMatch(s, t);
long endTime = System.currentTimeMillis();
long costTime = endTime-startTime;
System.out.println("暴力算法执行时间"+costTime);
System.out.println("暴力算法查找位置为"+indexByViolence);
//KMP匹配算法
startTime = System.currentTimeMillis();
int indexByKMP = kmpMatch(s, t);
endTime = System.currentTimeMillis();
costTime = endTime-startTime;
System.out.println("KMP执行时间"+costTime);
System.out.println("KMP查找位置为"+indexByViolence);
if (indexByKMP == indexByViolence) {
System.out.println("两种方法位置一致");
}else {
System.out.println("两种方法位置不一致");
}
}
private static int violenceMatch(String s, String t) {
//标记主串的
int i =0;
//标记子串的
int j =0;
while (i < s.length() && j < t.length()) {
if (s.charAt(i) == t.charAt(j)) {
i++;
j++;
}else{
i = i - j + 1;
j = 0;
}
}
//匹配成功,则j==t.length()
if (j == t.length()) {
return i-j;
}else {
return -1;
}
}
private static int kmpMatch(String s, String t) {
//构造一个子串的next数组,存储子串的字符next值
int[] next = new int[t.length()];
for (int i = 0; i < next.length; i++) {
//获取字符的next值
next[i] = getNextValue(i + 1,t);
}
//标记主串的
int i =0;
//标记子串的
int j =0;
while (i < s.length() && j < t.length()) {
if (s.charAt(i) == t.charAt(j)) {
i++;
j++;
}else{
//子串第一个字符匹配失败,则下次匹配时j的下标仍要为0,继续从子串第一个位置开始匹配,主串i右移一位。
if (j == 0) {
i = i+1;
}
//子串非第一个字符匹配失败,则下次匹配时子串应该从已匹配的子串最长匹配值开始匹配。主串i的位置不变。
else{
j = next[j-1];
}
}
}
//匹配成功,则j==t.length()
if (j == t.length()) {
return i-j;
}else {
return -1;
}
}
//获取next数组这里还可以再优化。这里处理的不好,会导致当数据过大时,kmp算法比暴力算法执行效率更慢。
private static int getNextValue(int tSonLength,String t) {
if (tSonLength == 1) {
return 0;
}
//前缀子串
String prefixT;
//后缀子串
String suffixT;
//最长前后缀匹配长度
int maxMatch = 0;
//有多少个字符串前后缀需要匹配
int matchNum = tSonLength-1;
//前缀子串的末尾下标 (字符串的第一个位置也是0)
int i = 1;
//后缀子串的起始下标
int j = tSonLength - 1;
while (matchNum > 0) {
//字符串前缀,substring方法是前闭后开的原则
prefixT = t.substring(0, i);
suffixT = t.substring(j, tSonLength);
if (prefixT.equals(suffixT)) {
maxMatch = i;
}
//前缀末尾下标右移
i++;
//后缀子串起始下标左移
j--;
//匹配次数减少一次
matchNum--;
}
return maxMatch;
}
}
字符串匹配问题(暴力匹配,KMP算法)
最新推荐文章于 2024-04-11 21:53:49 发布