在文本中找到模式字符串首次出现的位置。
文本:String text
模式字符串:String pattern
1、前缀:表示包含首位字符但不包含末位字符的子串
2、后缀:表示包含末位字符但不包含首位字符的子串
3、next数组
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Main2 { public static void main(String[] args) { String text="ABCDABEABCDABD"; String pttern="ABCDABD"; int next[]=kmpNext(pttern); System.out.println(Arrays.toString(next)); int result=kmpSearch(text,pttern,next); System.out.println(result); } public static int kmpSearch(String text, String pattern, int[] next) { for(int i = 0, j = 0; i < text.length(); i++) { while( j > 0 && text.charAt(i) != pattern.charAt(j)) {//必须有j>0,因为要确保j-1大于0! j = next[j-1]; } if(text.charAt(i) == pattern.charAt(j)) { j++; } if(j == pattern.length()) { return i - j + 1; } } return -1; } public static int[] kmpNext(String pattern) { int[] next = new int[pattern.length()]; next[0] = 0; for(int i = 1, j = 0; i < pattern.length(); i++) { //这时kmp算法的核心点 while(j > 0 && pattern.charAt(i) != pattern.charAt(j)) { j = next[j-1]; } if(pattern.charAt(i) == pattern.charAt(j)) { j++; } next[i] = j; } return next; } }
如上图所示,text="ABCDABEABCDABD",pattern="ABCDABD"。当比较到 i = 6,j = 6的时候,发现不匹配。此时对应的代码是
while( j > 0 && text.charAt(i) != pattern.charAt(j)) { j = next[j-1]; }
当前 j = 6,则 执行语句 j = next[j-1],j 的值更新为2。将 text[6]与pattern[2] 比较,发现还是不相等。继续循环。
当前 j = 2,则 执行语句 j = next[j-1],j 的值更新为0。将 text[6]与pattern[2] 比较,发现还是不相等。因为循环条件 j>0 不成立,结束循环。当前 i = 6, j = 0。执行一下代码。
if(text.charAt(i) == pattern.charAt(j)) { j++; } if(j == pattern.length()) { return i - j + 1; }
将 text[6]与pattern[2] 比较,发现不相等,所以第一个 if 语句不成立。
当前 j = 0 ,第二个 if 语句也不成立。当前循环结束,i++。当前 i = 7,j = 0。
1、 帮你把KMP算法学个通透
2、 很详尽的KMP算法