数据结构--KMP算法(字符串匹配算法)
两个字符串str1, str2,str2是否是str1的子串,若是,返回子串开始的位置。
利用前面匹配过的信息指导后面的匹配,可以起到加速的作用
某一个字符的最长前缀(不能包含最后一个元素)和最长后缀(不能包含第一个元素)的匹配长度组成一个数组next()数组
1.求str2的next()数组
0位置的默认-1
1位置的默认0
后面的都要求出其最长前缀和最长后缀的匹配长度 组成next数组
2.str1与str2进行匹配时,若在x,y位置不匹配,则查str2的next数组,找到y位置的最长前缀和最长后缀的匹配长度,然后将匹配长度对应到str1中的 j 位置
将str2的0位置对应到 j 位置,然后匹配x位置和最长前缀和最长后缀的匹配长度的下一个位置
再开始匹配,匹配的位置是x位置和str2中最长前缀和最长后缀匹配长度的下一个位置
开始匹配时:当x 位置与y位置不匹配时,则查str2的next数组,找到y位置的最长前缀和最长后缀的匹配长度
然后将匹配长度对应到str1中的 j 位置
将str2的0位置对应到 j 位置,
然后匹配x位置和最长前缀和最长后缀的匹配长度的下一个位置 : x位置与z位置
求next数组的方法:
0位置 -1
1位置 0
2位置 0 和1 位置相同为1,不同为0
其他位置:在求 i 位置的next数组时,找 i - 1位置的next数组指向的位置的下一个元素与 i - 1比较,、
如果相等,则 i 位置的next数组的值为 i - 1位置的next数组的值 + 1
如果不想等,则向上找到 i - 1 位置指向的next数组的 前缀的 下一个元素的 next数组的位置
然后比较它的下一个元素再与 i - 1位置的元素比较,如果相等,则为它的next数组 + 1,否则
重复上面的步骤,当找的位置没有前缀时,那么 i 位置的next数组的值为0
next数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | private static int [] nextArray(String str2) { if (str2 == null || str2.length() == 0 ) return null ; int [] next = new int [str2.length()]; next[ 0 ] = - 1 ; next[ 1 ] = 0 ; int num = 0 ; int index = 2 ; while (index < str2.length()){ if (str2.charAt( num ) == str2.charAt( index - 1 )) { next[index++] = ++num; } else if (num > 0 ) { num = next[num]; } if (num <= 0 ) { next[index++] = 0 ; num = 0 ; } } return next; } |
整体实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | public class KMP { public static int kmp(String str1, String str2){ if (str1 == null || str1.length() == 0 ) return - 1 ; int [] next = nextArray(str2); int i = 0 ; int j = 0 ; while (i < str1.length() && j < str2.length()){ if (str1.charAt( i ) == str2.charAt( j )){ i++; j++; } else { j = next[j]; } if (j == - 1 ){ i++; j++; } } if (j == str2.length()) return i - j; return - 1 ; } private static int [] nextArray(String str2) { if (str2 == null || str2.length() == 0 ) return null ; int [] next = new int [str2.length()]; next[ 0 ] = - 1 ; next[ 1 ] = 0 ; int num = 0 ; int index = 2 ; while (index < str2.length()){ if (str2.charAt( num ) == str2.charAt( index - 1 )) { next[index++] = ++num; } else if (num > 0 ) { num = next[num]; } if (num <= 0 ) { next[index++] = 0 ; num = 0 ; } } return next; } public static void main(String[] args){ int num = kmp( "abcabcababaccc" , "ababa" ); System.out.println(num); } } |