public static int[] getNextArray(char[] str2) {
if (str2.length == 1) { // 如果长度只有1,那么认为规定第一个为-1
return new int[] {-1};
}
int []next = new int[str2.length];
next[0] = -1; // 认为规定next数组前两个为-1和0
next[1] = 0;
int i = 2; // 从i=2开始填值
int cn = 0; // 我跳到的位置
while (i < next.length) {
if (str2[i - 1] == str2[cn]) { // 如果值对上,都往下走一个
next[i++] = ++cn;
}else if(cn > 0) { // str2还可以往回跳,如果跳到0代表都已经到头了
cn = next[cn];
}else {
next[i++] = 0; // 跳到0代表都已经到头了,那么说明该字母next值为0
}
}
return next;
}
KMP算法
1、先提出最长前缀和最长后缀的概念
例如abcabcd,字符d出记录到的最长后缀和最长前缀是abc,长度为3
2、当不匹配的时候我们将str2移动到j处
3、我们忽略了1到j处的字符,也就是我们认为1到j出的字符配不出一个完整的str2,可以用反证法求解
Java代码
package 数据结构;
public class Kmp {
public static int[] getNextArray(char[] str2) {
if (str2.length == 1) { // 如果长度只有1,那么认为规定第一个为-1
return new int[] {-1};
}
int []next = new int[str2.length];
next[0] = -1; // 认为规定next数组前两个为-1和0
next[1] = 0;
int i = 2; // 从i=2开始填值
int cn = 0; // 我跳到的位置
while (i < next.length) {
if (str2[i - 1] == str2[cn]) { // 如果值对上,都往下走一个
next[i++] = ++cn;
}else if(cn > 0) { // str2还可以往回跳,如果跳到0代表都已经到头了
cn = next[cn];
}else {
next[i++] = 0; // 跳到0代表都已经到头了,那么说明该字母next值为0
}
}
return next;
}
public static int getIndexOf(String s,String m) { // 父串,子串
if (s == null || m == null || m.length() < 1 || s.length() < m.length()) {
// 如果子串长度小于1 || 如果父串长度小于子串长度
return -1;
}
char []str1 = s.toCharArray();
char []str2 = m.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) { // str2和str1在头位置就不匹配
i1++; // str2继续往下走一个
}else {
i2 = next[i2];
}
}
return i2 == str2.length ? i1 - i2 : -1;
}
public static void main(String[] args) {
String str = "abcabcababaccc";
String match = "ababa";
System.out.println(getIndexOf(str,match));
}
}
C++代码
#include<iostream>
#include<string>
#include<string.h>
using namespace std;
void GetNextArray(char str2[],int *&next,int len){
if (len == 1){
next = new int[1];
next[0] = -1;
}
next[0] = -1;
next[1] = 0;
int i = 2;
int cn = 0;
while (i < len){
if (str2[i - 1] == str2[cn]){
next[i++] = ++cn;
}
else if (cn > 0){
cn = next[cn];
}
else{
next[i++] = 0; // 已经跳到头了
}
}
}
int getIndexOf(char str1[],char str2[],int len1,int len2){
if (str1 == NULL || str2 == NULL || len1 < len2 || len2 < 1){
return -1;
}
int *next = new int[len2];
GetNextArray(str2,next,len2);
int i1 = 0, i2 = 0;
while (i1 < len1 && i2 < len2){
if (str1[i1] == str2[i2]){
i1++;
i2++;
}
else if (next[i2] == -1){ // 是next碰到-1返回,不是str2
i1++;
}
else{
i2 = next[i2];
}
}
return i2 == len2 ? i1 - i2 : -1;
}
int main(){
char * str = "abcabcababaccc";
char * match = "ababa";
int len1 = strlen(str);
int len2 = strlen(match);
int res = getIndexOf(str, match, len1, len2);
printf("%d",res);
system("pause");
}