问题:如果有两个字符串str1,str2,我们要判断str2是否是str1的子字符串,我们可以采用暴力匹配算法,和KMP算法解决
1.暴力匹配算法
1.将两个字符串都变成字符数组;
char []s1=str1.toCharArray();
char []s2=str2.toCharArray();
2.判断s1[i]和s2[j]是否相等
(1.)不相等则i=i-j+1; j=0; 每次匹配失败s1的索引只往后移动一位
(2.)相等那么j++,i++
直到s1的空格和s2的D不匹配则进行(1)
完整java代码如下:
package com.yg.algorithm;/*
@author Mu_Mu
@date 2020/3/18 9:27
*/
public class ViolenceMatch {
public static void main(String[] args) {
String str1="hahahahehehahe";
String str2="hehehahe";
System.out.println("index:"+violenceMath(str1,str2));
}
public static int violenceMath(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;
}
}
}
2.KMP算法
1.建立一个部分匹配表:
部分匹配表:用一个一维数组next[]表示字符串中相同前缀后缀的最大长度,next[0]恒等于0;
next[j] = k 代表p[j] 之前的模式串子串中,有长度为k 的相同前缀和后缀
如字符串str=“A”;
它不能踩分为前缀和后缀所以它的部分匹配表为next:[0];
字符串str=“AA”;
它可以拆分为前缀A,和后缀A;
因为第二个A加进来后相同前缀和后缀的最大长度为1所以next[1]=1;
它的部分匹配表为 next:[0,1];
字符串str=“AAB”;
它可以拆分为前缀A,AA和后缀AB,B
因为B加进来后相同前缀和后缀的最大长度为0所以next[2]=0;
它的部分匹配表为 next:[0,1,0];
在KMP匹配中,当模式串中j 处的字符失配时,下一步用next[j]处的字符继续跟文本串匹配,相当于模式串向右移动j - next[j] 位。
构建部分匹配表
//获取到一个字符串(子串)的部分匹配表
public static int[] kmpNext(String dest) {
//创建一个next数组保存部分匹配值
int[] next = new int[dest.length()];
//当只有一个字符时匹配值为0
next[0]=0;
for (int i = 1, j = 0; i < dest.length(); i++) {
while (j>0&&dest.charAt(i) != dest.charAt(j)) {
//每次寻找部分匹配表j前面的一个匹配值
j=next[j-1];
}
//字符相等匹配值加一
if (dest.charAt(i) == dest.charAt(j)) {
j++;
}
next[i]=j;
}
return next;
}
除了s1[i]和s2[j]不相等时其余操作基本和暴力匹配相识
不相等时:
每次移动距离为失配字符前一个位置 - 失配字符前一个位置对应的next 值 j=next[j-1];
完整java代码实现:
package com.yg.algorithm;/*
@author Mu_Mu
@date 2020/3/18 10:58
*/
public class KmpAlgorithm {
public static void main(String[] args) {
String str1="hahahahheheheha";
String str2="heheheha";
int []next=kmpNext(str2);
System.out.println("index:"+kmpSearch(str1,str2,next));
}
//获取到一个字符串(子串)的部分匹配表
public static int[] kmpNext(String dest) {
//创建一个next数组保存部分匹配值
int[] next = new int[dest.length()];
//当只有一个字符时匹配值为0
next[0]=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;
}
public static int kmpSearch(String str1, String str2, int[] 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;
}
}
图片以及部分文字参考:
https://www.cnblogs.com/zhangtianq/p/5839909.html