应用场景 字符串匹配问题::
有一个字符串str1=“BBC ABCDAB ABCDABCDABDE”,和一个子串str2=“ABCDABD”
现在要判断str1 是否含有str2, 如果存在,就返回第一次出现的位置,如果没有,则返回-1
暴力匹配算法
如果用暴力匹配的思路,并假设现在str1匹配到i位置,子串str2匹配到 j 位置,则有
1)如果当前字符匹配成功( 即str1[i]==str2[j]),则i++, j++, 继续匹配下一个字符
2)如果失配(即str1[i]!=str2[j]) ,令i=i-(j-1), j=0。相当于每次匹配失败时,i
回溯,j被置为0.
3) 用暴力方法解决的话就会有大量的回溯,每次只移动一位,若是不匹配,移动到下一位接着判断,浪费了大量的时间。
4)暴力匹配算法实现.
public class ViolenceMatch {
public static void main(String[] args) {
String str1 = "32114 5456 89726541 32";
String str2 = "1 32";
int index = violenceMatch( str1, str2);
System.out.println(index);
}
//暴力匹配算法
public static int violenceMatch(String str1,String str2) {
char[] s1 = str1.toCharArray();
char[] s2 = str2.toCharArray();
int s1len = s1.length;
int s2len = s2.length;
int i = 0;//指向s1
int j = 0;//指向s2
while(i<s1len && j<s2len) {
//保证不越界
if(s1[i] == s2[j]) {
i++;
j++;
}else {
//未匹配成功
i = i - j + 1;
j = 0;
}
}
if(j == s2len) {
//前面有++
return i-j;
}else {
return -1;
}
}
}
KMP方法算法
利用之前判断过信息,通过一个next数组,保存模式串中前后最长公共子序列的长度,每次回溯时,通过next数组找到,前面匹配过的位置,省去了大量的计算时间
字符串匹配问题:
有一个字符串str1= “BBC ABCDABCDABDE”,和一个子串
str2="ABCDABD"现在要判断str1是否含有str2, 如果存在,就返回第一次出现的位置,如果没有,则返回-1
KMP主要作用 避免了子串内有重复字符的情况需要从头校验
如该字符串 结尾AB与头部AB相同 再校验到该最后的D不同的时候 可以直接比较子串头AB的后一位 (比较时原字符串指针不用动 需要移动的只是子串指针)
import java.util.Arrays;
public class KMPAlgorithm {
//KMP主要作用 避免了子串内有重复字符的情况需要从头校验
//如该字符串 结尾AB与头部AB相同 再校验到该最后的D不同的时候 可以直接比较子串头AB的后一位
public static void main(String[] args) {
String str1 = "BBC ABCDABCDABDE";
String str2 = "ABCDABD";
int[] next = kmpNext("ABCDABD");
System.out.println(Arrays.toString(next));
int index = kmpSearch(str1,str2,next);
System.out.println(index);
}
//获取一个字符串子串的部分匹配值表
public static int[] kmpNext(String dest) {
//创建一个数组 保存部分匹配值
int[] next = new int[dest.length()];
next[0] = 0;//如果字符串长度为1 则部分匹配值为0
for(int i = 1,j = 0;i<dest.length();i++) {
while(j > 0 && dest.charAt(i) != dest.charAt(j) ) {
j = next[j-1];
}
if(dest.charAt(i) == dest.charAt(j)) {
//满足则匹配值加一
j++;
}
next[i] = j;
}
return next;
}
//kmp搜索算法
public static int kmpSearch(String str1,String str2,int[] next) {
//str1原字符串 str2子串 next子串部分匹配表
for(int i = 0,j = 0;i<str1.length();i++) {
while(j>0 && str1.charAt(i) != str2.charAt(j)) {
//原字符串 指针不用动 需要移动的只是子串指针
j = next[j-1];
}
if(str1.charAt(i) == str2.charAt(j)) {
j++;
}
if(j == str2.length()) {
return i - j +1;
}
}
return -1;
}
}