๋ฌธ์ž์—ด ์•Œ๊ณ ๋ฆฌ์ฆ˜ - KMP ์•Œ๊ณ ๋ฆฌ์ฆ˜

KMP(Knuth-Morris-Pratt) ์•Œ๊ณ ๋ฆฌ์ฆ˜

  • ๋ถˆ์ผ์น˜๊ฐ€ ๋ฐœ์ƒํ•œ ํ…์ŠคํŠธ ๋ฌธ์ž์—ด์˜ ์•ž ๋ถ€๋ถ„์€ ๋‹ค์‹œ ๋น„๊ตํ•˜์ง€ ์•Š๊ณ  ์ผ์น˜ํ•˜๋Š” ๋ถ€๋ถ„ ๋ฌธ์ž์—ด๋ถ€ํ„ฐ ๋งค์นญ์„ ์ˆ˜ํ–‰ํ•จ์œผ๋กœ์จ ๋ฌธ์ž์—ด ๋น„๊ต ํšŸ์ˆ˜๋ฅผ ๋Œ€ํญ ๊ฐ์†Œ์‹œํ‚จ ์•Œ๊ณ ๋ฆฌ์ฆ˜
  • ํƒ€๊ฒŸ ๋ฌธ์ž์—ด์„ ๋Œ€์ƒ์œผ๋กœ ๋ถ€๋ถ„ ์ผ์น˜ ํ…Œ์ด๋ธ”์„ ์ž‘์„ฑํ•˜์—ฌ ํƒ€๊ฒŸ ๋ฌธ์ž์—ด ๋‚ด๋ถ€์—์„œ ์ค‘๋ณต๋˜๋Š” ๋ฌธ์ž์—ด์„ ๋น ๋ฅด๊ฒŒ ์ฐพ์Œ

    • ํƒ€๊ฒŸ ๋ฌธ์ž์—ด์˜ 1๋ฒˆ ์ธ๋ฑ์Šค ๋ฌธ์ž๋ถ€ํ„ฐ ๋งˆ์ง€๋ง‰ ์ธ๋ฑ์Šค ๋ฌธ์ž๊นŒ์ง€ ํ™•์ธํ•˜๋ฉฐ ๊ฐ ์ธ๋ฑ์Šค ๋ฌธ์ž๋ฅผ ์ถ”๊ฐ€ํ•œ ๋ถ€๋ถ„๋ฌธ์ž์—ด์˜ ์ ‘๋‘์‚ฌ์™€ ์ ‘๋ฏธ์‚ฌ๊ฐ€ ์ผ์น˜ํ•˜๋Š” ์ตœ๋Œ€ ๊ธธ์ด๋ฅผ ์ €์žฅ
  • ๋ถ€๋ถ„ ์ผ์น˜ ํ…Œ์ด๋ธ”์„ ์ด์šฉํ•ด ์ฃผ์–ด์ง„ ๋ฌธ์ž์—ด๊ณผ ํƒ€๊ฒŸ ๋ฌธ์ž์—ด์„ ๋น„๊ตํ•ด ๋งค์นญ์ด ์‹คํŒจํ–ˆ์„ ๋•Œ ํƒ€๊ฒŸ ๋ฌธ์ž์—ด ํฌ์ธํ„ฐ๊ฐ€ ๋Œ์•„๊ฐˆ ์ธ๋ฑ์Šค๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Œ
  • ์ฃผ์–ด์ง„ ๋ฌธ์ž์—ด ๊ธธ์ด๊ฐ€ M์ด๊ณ  ํƒ€๊ฒŸ ๋ฌธ์ž์—ด ๊ธธ์ด๊ฐ€ N์ผ ๋•Œ O(M+N)์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋กœ ์ผ์น˜ํ•˜๋Š” ํƒ€๊ฒŸ ๋ฌธ์ž์—ด์„ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.

๊ตฌํ˜„

Java
public class KMPTest {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        char[] text = br.readLine().toCharArray();              // ํƒ€๊ฒŸ ๋ฌธ์ž์—ด์„ ์ฐพ์•„์•ผํ•˜๋Š” ์ฃผ์–ด์ง„ ๋ฌธ์ž์—ด
        char[] target = br.readLine().toCharArray();            // ํƒ€๊ฒŸ ๋ฌธ์ž์—ด
        int textLen = text.length, targetLen = target.Length;
        int[] subPattern = new int[targetLen];                  // ๋ถ€๋ถ„ ์ผ์น˜ ํ…Œ์ด๋ธ”

        // ๋ถ€๋ถ„ ์ผ์น˜ ํ…Œ์ด๋ธ” ์ƒ์„ฑ
        for (int i=1, j=0; i<targetLen; i++) {      // i : ์ ‘๋ฏธ์‚ฌ ํฌ์ธํ„ฐ, j : ์ ‘๋‘์‚ฌ ํฌ์ธํ„ฐ
            while (j>0 && target[i]!=target[j]) j = subPattern[j-1];    // ๋ฌธ์ž์—ด์ด j์—์„œ ๋‹ฌ๋ผ์ง„๋‹ค๋Š” ๊ฒƒ์€ (j-1)๊นŒ์ง€ ์ผ์น˜ํ–ˆ์Œ์„ ์˜๋ฏธํ•˜๋ฏ€๋กœ ๋ถ€๋ถ„ ์ผ์น˜ ํ…Œ์ด๋ธ”์˜ (j-1)์ธ๋ฑ์Šค๋ฅผ ํ™•์ธ

            if (target[i]==target[j]) subPattern[i] = ++j;              // (j+1) ๊ธธ์ด๋งŒํผ ์ค‘๋ณต๋˜๋ฏ€๋กœ ์ด๋ฅผ ๋ถ€๋ถ„์ผ์น˜ํ…Œ์ด๋ธ”์— ์ €์žฅํ•˜๊ณ , ๋‹ค์Œ ๋น„๊ต๋ฅผ ์œ„ํ•ด j์ธ๋ฑ์Šค ์ฆ๊ฐ€ -> ++j
        }

        int cnt = 0;
        List<Integer> patternIdx = new ArrayList<Integer>();

        // ์ฃผ์–ด์ง„ ๋ฌธ์ž์—ด๊ณผ ํƒ€๊ฒŸ ๋ฌธ์ž์—ด์„ ๋น„๊ตํ•˜๋ฉฐ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธ
        for (int i=0, j=0; i<textLen; i++) {       // i : ํ…์ŠคํŠธ ํฌ์ธํ„ฐ , j: ํŒจํ„ด ํฌ์ธํ„ฐ
            while(j>0 && text[i]!=target[j]) j = subPattern[j-1];    // ๋ฌธ์ž์—ด์ด j์—์„œ ๋‹ฌ๋ผ์ง„๋‹ค๋Š” ๊ฒƒ์€ (j-1)๊นŒ์ง€ ์ผ์น˜ํ–ˆ์Œ์„ ์˜๋ฏธํ•˜๋ฏ€๋กœ ๋ถ€๋ถ„ ์ผ์น˜ ํ…Œ์ด๋ธ”์˜ (j-1)์ธ๋ฑ์Šค๋ฅผ ํ™•์ธ

            if (text[i]==target[j]){                        // ์ฃผ์–ด์ง„ ๋ฌธ์ž์—ด์˜ ๋ฌธ์ž์™€ ํƒ€๊ฒŸ ๋ฌธ์ž์—ด ๋ฌธ์ž๊ฐ€ ์ผ์น˜ํ•  ๋•Œ
                if (j==(targetLen-1)) {                     // ๋งŒ์•ฝ ํƒ€๊ฒŸ ๋ฌธ์ž์—ด์˜ ๋งˆ์ง€๋ง‰ ๋ฌธ์ž๊นŒ์ง€ ์ผ์น˜ํ–ˆ๋‹ค๋ฉด ํƒ€๊ฒŸ ๋ฌธ์ž์—ด์„ ์ฐพ์•˜์Œ์„ ์˜๋ฏธ
                    cnt++;                                  // ์ผ์น˜ํ•˜๋Š” ๋ฌธ์ž์—ด ๊ฐœ์ˆ˜ ์ฆ๊ฐ€
                    patternIdx.add((i+1) - targetLen);      // ์ผ์น˜ํ•˜๋Š” ๋ฌธ์ž์—ด์ด ์กด์žฌํ•˜๋Š” ์œ„์น˜ ์ €์žฅ
                    j = subPattern[j];                      // j๊นŒ์ง€ ์ผ์น˜ํ–ˆ์œผ๋ฏ€๋กœ ๋ถ€๋ถ„ ์ผ์น˜ ํ…Œ์ด๋ธ”์˜ j์ธ๋ฑ์Šค๋ฅผ ํ™•์ธ
                } else ++j;                                 // j๊ฐ€ ํŒจํ„ด์˜ ์ค‘๊ฐ„ ์ธ๋ฑ์Šค์ด๋ฏ€๋กœ ์•„์ง ๋“ค์—ฌ๋‹ค๋ด์•ผํ•  ํŒจํ„ด ์ธ๋ฑ์Šค๊ฐ€ ๋‚จ์Œ
            }
        }
    }
}