僅作個人總結,初學KMP不建議看本文
1.暴力匹配:
時間複雜度:O(mn)
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String S = scanner.next();
String T = scanner.next();
int index = Brute(S, T);
System.out.println(index);
scanner.close();
}
private static int Brute(String S, String T) { //S爲主串,T爲模式串
int i = 0, j = 0;
while (i < S.length() && j < T.length()) {
if (S.charAt(i) == T.charAt(j)) {
i++;
j++;
} else { //回到主串的下一個位置繼續匹配
i = i - j + 1;
j = 0;
}
}
if (j == T.length())
return i - T.length();
else
return -1;
}
}
2.KMP
時間複雜度:O(m+n),m、n分別爲主串和模式串的長度
- next數組的含義:在模式串的第
j
個字符與主串失配時,則跳到模式串的next[j]
位置重新與主串當前位置進行比較,例如next[1] = 0
,模式串從下標爲0的開始與主串下標爲i
的位置繼續匹配。 - 注意邊界,設
next[0] = -1
,KMP匹配的時候不會訪問next[0]
- 從原理上理解:next數組是由模式串的最長公共前後綴PM得來的,爲了方便,有時候會將得到的PM數組整體右移一位,空下的next[0]置爲-1,然後將所有的PM值+1,這種理解方式便於做題的時候快速得到next數組,如果題目中給的下標是從0開始的,那麼右移以後就不用+1了。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String S = scanner.next();
String T = scanner.next();
int index = KMP(S, T, getnext(T));
System.out.println(index);
scanner.close();
}
private static int[] getnext(String T) {
int i = 0, j = -1; //設j爲-1,第一次進入循環一定使next[1] = 0;
int[] next = new int[T.length() + 1];
next[0] = -1;
while(i < T.length()){
if(j == -1 || T.charAt(i) == T.charAt(j)){ //小技巧
i++;
j++;
next[i] = j;
}else{
j = next[j];
}
}
/*
for(int a : next) {
System.out.print(a + " ");
}*/
return next;
}
private static int KMP(String S, String T, int[] next) { //S爲主串,T爲模式串
int i = 0, j = 0;
while (i < S.length() && j < T.length()) {
if (j == 0 || S.charAt(i) == T.charAt(j)) { //第一個字符失配,不需要訪問next[0],兩個下標均加1即可
i++;
j++;
} else { //主串不回溯,模式串回到下標爲next[j]
j = next[j];
}
}
if (j == T.length())
return i - T.length();
else
return -1;
}
}
貼一道關於next數組的題目:1392. 最長快樂前綴