网上代码很多,不过也有很多都是错的。至于原理,我也讲不清,首先明白next数组是怎么求,至少你要先明白求最长公共前缀和后缀,人为规定前缀不包含最后一个字符,后缀不包含第一个字符,然后利用next数组就不用暴力匹配,pattern会滑动一段距离。
#include <iostream>
#include <string>
#define N 100
using namespace std;
int next[N];
void getNext(string s) {
int i = 0;
int k = -1;
next[i] = k;
while (i < s.length()) {
if (k == -1 || s[k] == s[i]) {
i++;
k++;
next[i] = k;
} else {
k = next[k];
}
}
}
int getIndex(string s1, string s2) {
int i = 0;
int j = 0;
while (i < s1.length() && j <s2.length()) {
if (s1[i] == s2[j]) {
i++;
j++;
} else if (next[j] == -1) {
i++;
} else {
j = next[j];
}
}
if (j == s2.length()) {
return i - s2.length();
} else {
return -1;
}
}
int main() {
string str1, str2;
str1 = "cnlabaabcabaklm";
str2 = "abaabcaba";
getNext(str2);
for (int i = 0; i < str2.length(); i++) {
printf("%d ", next[i]);
}
printf("\n%d", getIndex(str1, str2));
return 0;
}
public class KMPAlgorithm {
/*
kmp算法,判断子串问题
*/
public static int getIndexOf(String s, String m) {
if (s == null || m == null || m.length() < 1 || s.length() < m.length()) {
return -1;
}
char[] ss = s.toCharArray();
char[] ms = m.toCharArray();
int si = 0;
int mi = 0;
int[] next = getNextArray(ms);
for (int i : next) {
System.out.print(i + " ");
}
while (si < ss.length && mi < ms.length) {
if (ss[si] == ms[mi]) {
si++;
mi++;
} else if (next[mi] == -1) {
si++;
} else {
mi = next[mi];
}
}
return mi == ms.length ? si - mi : -1;
}
public static int[] getNextArray(char[] ms) {
if (ms.length == 1) {
return new int[] { -1 };
}
int[] next = new int[ms.length];
next[0] = -1;
next[1] = 0;
int pos = 2;
int cn = 0;
while (pos < next.length) {
if (ms[pos - 1] == ms[cn]) {
next[pos++] = ++cn;
} else if (cn > 0) {
cn = next[cn];
} else {
next[pos++] = 0;
}
}
return next;
}
public static void main(String[] args) {
String str = "abcabcababaccc";
String match = "ababa";
System.out.println("\n" + getIndexOf(str, match));
}
}