본문 바로가기

PS/Problems

[Java] 백준 1786번 찾기 - KMP

https://www.acmicpc.net/problem/1786

 

1786번: 찾기

첫째 줄에, T 중간에 P가 몇 번 나타나는지를 나타내는 음이 아닌 정수를 출력한다. 둘째 줄에는 P가 나타나는 위치를 차례대로 공백으로 구분해 출력한다. 예컨대, T의 i~i+m-1번 문자와 P의 1~m

www.acmicpc.net

KMP 알고리즘을 사용해야 한다.

역시 기초만 다루는데도 어려워서 플5로 책정되어있다

 

import java.util.*;
import java.io.*;

public class p1_1786{
    static FastScanner fs = new FastScanner();
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static PrintWriter pw = new PrintWriter(System.out);

    static int[] pi;
    public static void main(String[] args) throws IOException{
        char[] str1 = br.readLine().toCharArray();
        char[] str2 = br.readLine().toCharArray();
        pi = new int[str2.length];
        kmp(str2);

        int p2 = 0;
        List<Integer> where = new LinkedList<>();

        for (int p1=0;p1<str1.length;p1++){
            while (p2 > 0 && str1[p1] != str2[p2]){
                p2 = pi[p2 - 1];
            }

            if (str1[p1] == str2[p2]){
                if (p2 == str2.length - 1){
                    where.add(p1 - p2 + 1);
                    p2 = pi[p2];
                }
                else p2++;
            }
        }
        pw.println(where.size());
        for (Integer i : where) pw.printf("%d ", i);
        
        pw.close();
    }

    static void kmp(char[] str){
        int k = 0, len = str.length;
        for (int i=1;i<len;i++){
            while (k > 0 && str[i] != str[k]){
                k = pi[k - 1];
            }

            if (str[i] == str[k]){
                pi[i] = ++k;
            }
        }
    }

//    ----------input function----------

    static void sort(int[] a){
        ArrayList<Integer> L = new ArrayList<>();
        for (int i : a) L.add(i);
        Collections.sort(L);
        for (int i = 0; i < a.length; i++) a[i] = L.get(i);
    }

    static class FastScanner{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer("");
        String next(){
            while (!st.hasMoreTokens()){
                try{
                    st = new StringTokenizer(br.readLine());
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt(){
            return Integer.parseInt(next());
        }

        int[] readArray(int n){
            int[] a = new int[n];
            for (int i = 0; i < n; i++) a[i] = nextInt();
            return a;
        }

        long nextLong(){
            return Long.parseLong(next());
        }
    }
}