BF
- 最简单易懂的写法,也是性能最差的写法。
- 最坏时间复杂度:
O(n*m)
public static int BF(String str1,String str2,int pos) {
int lenstr1 = str1.length();
int lenstr2 = str2.length();
if (pos < 0 || pos > lenstr1) {
return -1;
}
int i = pos;
int j = 0;
while (i < lenstr1 && j < lenstr2) {
if (str1.charAt(i) == str2.charAt(j)) {
i++;
j++;
} else {
i = i - j + 1;
j = 0;
}
}
if (j >= str2.length()) {
return i - j;
} else {
return -1;
}
}
KMP
- 主要分为两步,第一步,求
next
数组,第二步,匹配
next数组
next
数组是对于一个字符串而言的,比如我们求str2
在str1
中是否存在,如果存在返回str2
在str1
中的起始索引,那么我们就要求出str2
的next
数组- 那字符串的
next
数组怎么求呢。
- 假设字符串
abcabct
,对于t
,它前面的字符串是abcabc
,abcabc
的前缀为a
,ab
,abc
,abca
,abcab
;它的后缀c
,bc
,abc
,cabc
,bcabc
(前缀不能包含最后一位,后缀不能包含最前一位,所以前缀不能是abcabc
,后缀也不能是abcabc
)。前缀与后缀中最长的相等的字符串是abc
,所以t
的next
数组值为abc
的长度,即为3
。 - 同理,对于
c
,它前面的字符串为abcab
,前缀为a
,ab
,abc
,abca
;后缀为b
,ab
,cab
,bcab
。前缀与后缀中最长的相等的字符串是ab
,所以c
位置next
数组值为2
。 - 倒数第
3
个字符b
求法类推…… - 对于最开始的
a
,由于它是第一个字符,前面没有字符串,所以人为规定它的next
数组值为-1
,也可以规定为0
,但定为-1
对后面有用,第二个字符b
前面只有a
,而前缀和后缀不能包含最后一个和第一个字符,所以第二个字符的next
为0
。除了第一个第二个特殊,其他的均用以上方法求next
数组值 - 所以,对于字符串
abcabct
,它的next
数组值为[-1,0,0,0,1,2,3]
匹配
- 得到
next
数组后怎么用呢? - 比如
str1
为abcabckxyz
,str2
为abcabct
,显然是k
和t
不相等,而对于str2
,t
位置next
数组值为3
,所以就从t
开始往前找3
位,找到了str2
中的第二个a
,它对应str1
中的第二个a
,就将str2
后移,使str2
的起始位置元素对应str1
中找到的这个元素。 - 为什么这么做呢?
- 首先,
k
和t
不相等,说明k
和t
的前面都是相等的
- 如图,
str1
从i
位置开始,str2
从0
位置开始,进行匹配,到X
、Y
处发现不等,那么第一坨与第二坨肯定是相等的。并且第一坨中任意一段一定与第二坨中对应段上的字符串相等。

- 而
t
的next
值表示t
前面的串中最长的相等的前缀和后缀的长度
- 如图,由上面加粗字体我们可以知道,第三坨字符串肯定与后缀段字符串相等,由
Y
位置的next
数组值我们知道Y
前面的串中最长的相等的前缀与后缀,也就是图中前缀段字符串与后缀段字符串相等,它们的长度就是Y
位置的next
数组值。

- 所以,前缀段字符串与后缀段字符串相等,后缀段字符串与第三坨字符串相等,那么前缀段字符串就与第三坨字符串相等,那么我们就可以把第三坨字符串与前缀段字符串移到对应位置上,因为它们相等,所以下次匹配就从
X
位置和前缀字符串的后一个位置开始匹配。

- 也就是将下图中的
X
位置与Z
位置开始匹配,如果相同,分别匹配后一位,如果不相同,就采用上述方法,根据Z
位置的next
数组值,得到Z
的前缀段字符串和后缀段字符串,这里不再赘述。 - 如果
Z
位置的next
数组值为0
,说明Z
前面的字符串没有相等的前缀段与后缀段,那么把str2
的0
位置与str1
的X
位置对齐即可。

代码
public static int getIndexOf(String s1,String s2){
if(s1 == null || s2 == null || s2.length() < 1 || s1.length() < s2.length()){
return -1;
}
char[] str1 = s1.toCharArray();
char[] str2 = s2.toCharArray();
int i1 = 0;
int i2 = 0;
int [] next = getNextArray(str2);
while (i1 < str1.length && i2 < str2.length){
if(str1[i1] == str2[i2]){
i1 ++;
i2 ++;
}else{
if(next[i2] == -1){
i1 ++;
}else{
i2 = next[i2];
}
}
}
return i2 == str2.length ? i1 - i2 : -1;
}
private static int[] getNextArray(char[] str) {
if(str.length == 1){
return new int[]{-1};
}
int[] next = new int[str.length];
next[0] = -1;
next[1] = 0;
int i = 2;
int cn = 0;
while (i < next.length){
if(str[i - 1] == str[cn]){
next[i ++] = ++cn;
}else if(cn > 0){
cn = next[cn];
}else{
next[i ++] = 0;
}
}
return next;
}
public static void main(String[] args) {
System.out.println(getIndexOf("abdefbcd","bcd"));
}
SunDay
public class TestSunDay {
public static void main(String[] args) {
String source = "acfdedfacfdbea";
String target = "acfdbe";
int i = SunDay(source.toCharArray(),target.toCharArray(),0);
System.out.println("匹配结果:" + i);
}
public static int SunDay(char[] tempS, char[] tempT,int indexS) {
if(indexS >= tempS.length)
return -1;
int indexT = 0;
int count = 0;
for (int i = indexS; i < indexS + tempT.length; i++) {
if (tempS[i] == tempT[indexT]) {
indexT ++;
count ++;
} else {
break;
}
}
if (count == tempT.length) {
return indexS;
}
if(indexS + tempT.length < tempS.length){
int i = check(tempS[indexS + tempT.length],tempT);
if( i == -1){
indexS += tempT.length;
return SunDay(tempS, tempT, indexS);
}else{
indexS = indexS + tempT.length - i;
return SunDay(tempS, tempT, indexS);
}
}else{
return -1;
}
}
public static int check(char c, char[] tempT) {
for (int i = 0; i < tempT.length; i++) {
if(c == tempT[i])
return i;
}
return -1;
}
}