KMP算法
KMP算法最关键的一步在于寻找最长公共前缀后缀长度
而回溯的长度 = 已匹配字符数 - 失配字符前一个字符的最长公共前缀后缀长度
- 寻找前缀后缀最长公共元素长度:
- 如果给定的模式串为“abab”,那么它的各个子串的前缀后缀的公共元素的最大长度数组a为0 0 1 2:
- 相应的回溯数组next为a向右平移一位,且b[0]=-1; (可选)
-
可以把《最大长度表》看做是next 数组的雏形,甚至就把它当做next 数组也是可以的,区别不过是怎么用的问题。
模式串中在j 处的字符跟文本串在i 处的字符匹配失配时,下一步用next [j] 处的字符(或a[j-1]处字符)继续跟文本串i 处的字符匹配,相当于模式串向右移动 j - next[j] 位。
这里可以这样理解:
已匹配字符长度:3 失配字符j=3处前一位字符A的最大共同前后缀长度为1
大白话说就是,你在哪里匹配失败了,你就得尽可能多地移动你的模式字符串,移动多少字符数的依据主要就是看
失配字符前一个字符的最长后缀长度。
直接上代码:
import java.util.Arrays; public class kmp { public static int[] next; public static void main(String[] args) { String str1 = "ABCABD"; getNext(str1); System.out.println(Arrays.toString(next)) ; int i = kmpSearch("ABABCABD", "ABCABD"); System.out.println(i) ; } public static void getNext(String str1){ char[] s1 = str1.toCharArray(); int length = s1.length; next = new int[length]; next[0] = 0; for(int i = 1,j = 0; i < length; i++){ while(j > 0 && s1[i] != s1[j]){ j = next[j-1]; } if(s1[i] == s1[j]){ j++; } next[i] = j; } } public static int kmpSearch(String str1, String str2){ char[] s1 = str1.toCharArray(); char[] s2 = str2.toCharArray(); for (int i = 0, j = 0; i < str1.length(); i++){ while (j > 0 && s1[i] != s2[j]){ j = next[j-1]; } if(s1[i] == s2[j]){ j++; } if( j == str2.length()){ return i - j + 1; } } return -1; } }
设模式串长度为m,待匹配字符串长度为n
时间复杂度为o(m)+o(n)
如有错误,麻烦在评论区指出