import java.util.ArrayList;
import java.util.List;
public class String2Utils {
//https://mp.weixin.qq.com/s/3gYbmAAFh08BQmT-9quItQ --小灰2020年度
//KMP算法的整体思路:在已匹配的前缀当中寻找到最长可匹配后缀子串和最长可匹配前缀子串,在下一轮直接把两者对齐,从而实现模式串的快速移动。
// KMP算法主体逻辑。str是主串,pattern是模式串
public static int kmp(String str, String pattern) {
//预处理,生成next数组
int[] next = getNexts(pattern);
int j = 0;
//主循环,遍历主串字符
for (int i = 0; i < str.length(); i++) {
while (j > 0 && str.charAt(i) != pattern.charAt(j)) {
//遇到坏字符时,查询next数组并改变模式串的起点
j = next[j];
}
if (str.charAt(i) == pattern.charAt(j)) {
j++;
}
if (j == pattern.length()) {
//匹配成功,返回下标--首次出现位置
return i - pattern.length() + 1;
}
}
return -1;
}
// 生成Next数组
private static int[] getNexts(String pattern) {
int[] next = new int[pattern.length()];
int j = 0;
for (int i = 2; i < pattern.length(); i++) {
while (j != 0 && pattern.charAt(j) != pattern.charAt(i - 1)) {
//从next[i+1]的求解回溯到 next[j]
j = next[j];
}
if (pattern.charAt(j) == pattern.charAt(i - 1)) {
j++;
}
next[i] = j;
}
return next;
}
//获取所有匹配子字符串的位置
// KMP算法主体逻辑。str是主串,pattern是模式串
public static List<Integer> getAllIndexByKmp(String str, String pattern) {
List<Integer> indexs=new ArrayList<>();
//预处理,生成next数组
int[] next = getNexts(pattern);
int j = 0;
//主循环,遍历主串字符
for (int i = 0; i < str.length(); i++) {
while (j > 0 && str.charAt(i) != pattern.charAt(j)) {
//遇到坏字符时,查询next数组并改变模式串的起点
j = next[j];
}
if (str.charAt(i) == pattern.charAt(j)) {
j++;
}
if (j == pattern.length()) {
j=0;
//匹配成功,返回下标--首次出现位置
indexs.add(i - pattern.length() + 1);
}
}
return indexs;
}
public static void main(String[] args) {
/*String str = "ATGTGAGCTGGTGTGTGCFAA";
String pattern = "GTGTGCF";
int index = kmp(str, pattern);
System.out.println("首次出现位置:" + index);*/
String str = "ATGTGAGCTGGTGTGTGCFAA";
String pattern = "GTG";
List<Integer> ind=getAllIndexByKmp(str, pattern);
System.out.println("所有出现位置:" + ind);
System.out.println("匹配个数:" + ind.size());
}
}
String-KMP算法
最新推荐文章于 2022-01-25 11:55:25 发布