字符串匹配(KMP)

僅作個人總結,初學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. 最長快樂前綴

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章