๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
์•Œ๊ณ ๋ฆฌ์ฆ˜/๋ฐฑ์ค€

[BOJ 9252] LCS2

by ๐Ÿณ Laboon 2025. 4. 8.

๋ฌธ์ œ ์ •๋ฆฌ

LCS(Longest Common Subsequence, ์ตœ์žฅ ๊ณตํ†ต ๋ถ€๋ถ„ ์ˆ˜์—ด) ๋ฌธ์ œ
๋‘ ์ˆ˜์—ด์ด ์ฃผ์–ด์ง„๋‹ค.
๋ถ€๋ถ„ ์ˆ˜์—ด์„ ์ฐพ๋Š”๋‹ค.
๊ทธ ์ค‘ ๊ฐ€์žฅ ๊ธด ๊ฒƒ์„ ์ฐพ๋Š”๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด, ACAYKP์™€ CAPCAK์˜ LCS๋Š” ACAK๊ฐ€ ๋œ๋‹ค.
LCS์˜ ๊ธธ์ด์™€ LCS๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.

์ œํ•œ ์‚ฌํ•ญ

0.1s, java11: 0.4s
๊ฐ ์ˆ˜์—ด = ์ตœ๋Œ€ 1000๊ธ€์ž
LCS๊ฐ€ 0์ธ ๊ฒฝ์šฐ, ๊ธธ์ด๋งŒ ์ถœ๋ ฅ

ํ•ต์‹ฌ ํฌ์ธํŠธ

LCS๋ฅผ naiveํ•˜๊ฒŒ ์ฐพ์•„๋ณด์ž.

  • A ์ˆ˜์—ด๊ณผ B ์ˆ˜์—ด์ด ์žˆ์„ ๋•Œ, B ์ˆ˜์—ด๋กœ A ์ˆ˜์—ด์˜ LCS๋ฅผ ์ฐพ๋Š”๋‹ค๋ฉด O(N^3)์ด ๋ฐœ์ƒํ•œ๋‹ค.
  • B ์ˆ˜์—ด์˜ ๊ฐ ๊ธ€์ž๋ฅผ ์ฒซ ๋ถ€๋ถ„ ์ˆ˜์—ด์˜ ๊ธ€์ž๋กœ ์ƒ๊ฐํ•˜๊ณ  ์ฐพ๋Š”๋‹ค๋ฉด 1000 ๊ธ€์ž์— ๋Œ€ํ•ด ๊ฐ ๊ฐ 1000 - i ๊ธ€์ž ์ˆ˜๋ฅผ ์—ฐ์‚ฐํ•ด์•ผ ๋œ๋‹ค. (N^2)
  • ๊ฐ N^2์˜ ๋ถ€๋ถ„ ์ˆ˜์—ด์˜ ๊ธ€์ž๊ฐ€ A ์ˆ˜์—ด์— ์žˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผํ•œ๋‹ค. (N^3)
  • ์™„์ „ ํƒ์ƒ‰์œผ๋กœ๋Š” ๋ถˆ๊ฐ€๋Šฅ ํ•œ ๊ฒƒ์„ ์•Œ๊ฒŒ ๋๋‹ค.

DP ๋˜๋Š” ๊ทธ๋ฆฌ๋””, ์ด๋ถ„ ํƒ์ƒ‰๊ณผ ๊ฐ™์€ ํšจ์œจ์ ์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์„ ํƒํ•ด์•ผ๋œ๋‹ค.
ํ•ด๋‹น ๋ฌธ์ œ๋Š” ์œ ๋ช…ํ•œ LCS ๋ฌธ์ œ๋ผ์„œ DP์ธ ๊ฒƒ์€ ์ž๋ช…ํ•˜๋‹ค.
ํ•˜์ง€๋งŒ, ์ฒ˜์Œ ๋ฌธ์ œ๋ฅผ ๋ดค์„ ๋•Œ DP์ธ์ง€ ์–ด๋–ป๊ฒŒ ์•Œ ์ˆ˜ ์žˆ์„๊นŒ?

ํ‚ค ํฌ์ธํŠธ๊ฐ€ 3๊ฐ€์ง€ ์žˆ๋‹ค.

  1. ๋ถ€๋ถ„ ์ˆ˜์—ด -> B ์ˆ˜์—ด ์ค‘ ์•ž ๋ถ€๋ถ„์˜ ์ž‘์€ ์ˆ˜์—ด์— ๋‹ค์Œ ๊ธ€์ž๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค๋ฉด ๋ฉ”๋ชจ์ œ์ด์…˜์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  2. ๊ฐ€์žฅ ๊ธด -> ์ตœ์žฅ์„ ์ฐพ๋Š” ๋ฌธ์ œ์—์„œ๋Š” DP๋ฅผ ์˜์‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.
  3. ์‹œ๊ฐ„ ์ œํ•œ -> ์ฑ„ 1์ดˆ๋„ ์•ˆ๋˜๋Š” ์งง์€ ์‹œ๊ฐ„์€ ์„ ํ˜• ํƒ์ƒ‰์ด๋‚˜ ์ƒ์ˆ˜ ํƒ์ƒ‰์—์„œ ์ฃผ๋กœ ๋‚˜์˜จ๋‹ค. DP๋ฅผ ์˜์‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•ต์‹ฌ ๋กœ์ง

ACAYKP vs CAPCAK DP Table

 

DP ํ…Œ์ด๋ธ”์„ ๊ทธ๋ ค๋ณด๋ฉด, ๊ทธ๋ฆผ๊ณผ ๋™์ผํ•˜๋‹ค. ACAYKP ์—์„œ ๋ฐ”๋ผ๋ณด์ž.

A๊ฐ€ CAPCAK์—์„œ A๋ฅผ ๋งŒ๋‚œ ์ˆœ๊ฐ„๋ถ€ํ„ฐ LCS๋Š” 1์ด๋‹ค.

C๋Š” ์ด์ „์— A์˜ LCS๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, CAPCAK์—์„œ C๋ฅผ ๋งŒ๋‚˜์ง€ ๋ชปํ•œ๋‹ค๋ฉด ๋ถ€๋ถ„ ์ˆ˜์—ด A์˜ LCS๊ฐ€ AC์˜ LCS๊ฐ€ ๋  ๊ฒƒ์ด๋‹ค.

๋งŒ์•ฝ, C๋ฅผ ๋งŒ๋‚œ๋‹ค๋ฉด C๋ฅผ ๋งŒ๋‚œ ์‹œ์ (๋ฐ”๋กœ ์ด์ „ ๋ถ€๋ถ„ ์ˆ˜์—ด)๊นŒ์ง€์˜ LCS + 1 ๊ฐœ์ด๋‹ค.

 

์ฆ‰ 2๊ฐ€์ง€ ์ผ€์ด์Šค๋งŒ ์กด์žฌํ•˜๋ฏ€๋กœ ์ ํ™”์‹์„ ๋„์ถœ ํ•  ์ˆ˜ ์žˆ๋‹ค.

if ch1 == ch2 DP[i][j] = DP[i-1][j-1] + 1

else DP[i][j] = max(DP[i-1][j], DP[i][j-1])

 

๊ทธ๋Ÿผ, LCS์˜ ๋ฌธ์ž๋ฅผ ๋ฝ‘์•„๋‚ด๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•  ์ˆ˜ ์žˆ์„๊นŒ? -> trace

๋‘ ์ˆ˜์—ด์˜ ๊ธธ์ด๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์„œ dp ํ…Œ์ด๋ธ”์„ ํ†ตํ•ด ์ถ”์  ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

if (A์™€ B์˜ ๊ธธ์ด๊ฐ€ ๊ฐ๊ฐ <= 0) return

else if (๋ฌธ์ž๊ฐ€ ๊ฐ™๋‹ค๋ฉด) ๋ฌธ์ž ์ €์žฅ

else DP ํ…Œ์ด๋ธ”์—์„œ A, B๋ฅผ ํ†ตํ•œ ๊ฒฝ๋กœ ์ค‘ ๋” ํฐ ๊ฐ’์œผ๋กœ ์ถ”์ 

์ฝ”๋“œ

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Main {

    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    static StringBuilder sb = new StringBuilder();
    static int[][] dp = new int[1001][1001];
    static String str1, str2;

    public static void main(String[] args) throws IOException {
        str1 = br.readLine();
        str2 = br.readLine();

        for (int i = 0; i < str1.length(); i++) {
            for (int j = 0; j < str2.length(); j++) {
                if (str1.charAt(i) == str2.charAt(j)) {
                    dp[i + 1][j + 1] = dp[i][j] + 1;
                } else {
                    dp[i+1][j+1] = Math.max(dp[i][j+1], dp[i+1][j]);
                }
            }
        }

        int maxLcsLength = dp[str1.length()][str2.length()];
        sb.append(maxLcsLength).append('\n');
        trace(str1.length(), str2.length());

        bw.write(sb.toString());
        bw.flush();
    }

    static void trace(int s1Idx, int s2Idx) {
        if (s1Idx <= 0 || s2Idx <= 0) {
            return;
        } else if (str1.charAt(s1Idx - 1) == str2.charAt(s2Idx - 1)) {
            trace(s1Idx - 1, s2Idx - 1);
            sb.append(str1.charAt(s1Idx - 1));
        } else if (dp[s1Idx - 1][s2Idx] >= dp[s1Idx][s2Idx - 1]) {
            trace(s1Idx - 1, s2Idx);
        } else {
            trace(s1Idx, s2Idx - 1);
        }
    }

}