Algorithm/BOJ

[Boj_9251] LCS

jeong_ii 2023. 11. 10. 14:52

๐Ÿ“Ž ๋ฌธ์ œ ๋งํฌ

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

 

9251๋ฒˆ: LCS

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

www.acmicpc.net

 

โ–ธ ๋ฌธ์ œ

LCS(Longest Common Subsequence, ์ตœ์žฅ ๊ณตํ†ต ๋ถ€๋ถ„ ์ˆ˜์—ด)๋ฌธ์ œ๋Š” ๋‘ ์ˆ˜์—ด์ด ์ฃผ์–ด์กŒ์„ ๋•Œ, ๋ชจ๋‘์˜ ๋ถ€๋ถ„ ์ˆ˜์—ด์ด ๋˜๋Š” ์ˆ˜์—ด ์ค‘ ๊ฐ€์žฅ ๊ธด ๊ฒƒ์„ ์ฐพ๋Š” ๋ฌธ์ œ์ด๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ACAYKP์™€ CAPCAK์˜ LCS๋Š” ACAK๊ฐ€ ๋œ๋‹ค.

 

โ–ธ ์ž…๋ ฅ

์ฒซ์งธ ์ค„๊ณผ ๋‘˜์งธ ์ค„์— ๋‘ ๋ฌธ์ž์—ด์ด ์ฃผ์–ด์ง„๋‹ค. ๋ฌธ์ž์—ด์€ ์•ŒํŒŒ๋ฒณ ๋Œ€๋ฌธ์ž๋กœ๋งŒ ์ด๋ฃจ์–ด์ ธ ์žˆ์œผ๋ฉฐ, ์ตœ๋Œ€ 1000๊ธ€์ž๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋‹ค.

 

โ–ธ ์ถœ๋ ฅ

์ฒซ์งธ ์ค„์— ์ž…๋ ฅ์œผ๋กœ ์ฃผ์–ด์ง„ ๋‘ ๋ฌธ์ž์—ด์˜ LCS์˜ ๊ธธ์ด๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.

 

๐Ÿ“ ๋ฌธ์ œ ์ •๋ณด

  • ๐Ÿฅ‡ ๋ฌธ์ œ ๋ ˆ๋ฒจ : ๊ณจ๋“œ 1
  • ๐Ÿ””  ๋ฌธ์ œ ์œ ํ˜• : ๋‹ค์ด๋‚˜๋ฏน ํ”„๋กœ๊ทธ๋ž˜๋ฐ, ๋ฌธ์ž์—ด
  • ๐Ÿ’ฌ  ํ’€์ด ์–ธ์–ด : JAVA

 

๐Ÿ” ๋™์  ๊ณ„ํš๋ฒ•(Dynamic Programing, DP )์ด๋ž€ ?

  • ํฐ ๋ฌธ์ œ๋ฅผ ์ž‘์€ ๋ฌธ์ œ๋กœ ๋‚˜๋ˆ„์–ด ํ‘ธ๋Š” ๋ฌธ์ œ๋ฅผ ์ผ์ปซ๋Š” ๋ง์ด๋‹ค.
  • DP์—์„œ๋Š” ์ž‘์€ ๋ถ€๋ถ„์˜ ๋ฌธ์ œ๋“ค์ด ๋ฐ˜๋ณต๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋ถ„ํ•  ์ •๋ณต๊ณผ๋Š” ๋‹ค๋ฅด๋‹ค.
    • ๋ถ„ํ•  ์ •๋ณต์—์„œ๋Š” ๋™์ผํ•œ ๋ถ€๋ถ„ ๋ฌธ์ œ๊ฐ€ ๋ฐ˜๋ณต์ ์œผ๋กœ ๊ณ„์‚ฐ๋˜์ง€ ์•Š๋Š”๋‹ค.

 

๐Ÿ”ธ Dynamic Programing ๋ฐฉ๋ฒ•

  • ๋ชจ๋“  ์ž‘์€ ๋ฌธ์ œ๋“ค์€ ํ•œ ๋ฒˆ๋งŒ ํ’€์–ด์•ผ ํ•œ๋‹ค.
  • ๋”ฐ๋ผ์„œ ์ •๋‹ต์„ ๊ตฌํ•œ ์ž‘์€ ๋ฌธ์ œ๋ฅผ ๋ฉ”๋ชจํ•ด ๋†“๊ณ ,
  • ๊ทธ๋ณด๋‹ค ํฐ ๋ฌธ์ œ๋ฅผ ํ’€์–ด๋‚˜๊ฐˆ ๋•Œ, ๋˜‘๊ฐ™์€ ์ž‘์€ ๋ฌธ์ œ๊ฐ€ ๋‚˜ํƒ€๋‚˜๋ฉด ๋ฉ”๋ชจํ•ด ๋‘์—ˆ๋˜ ์ž‘์€ ๋ฌธ์ œ์˜ ๊ฒฐ๊ด๊ฐ’์„ ์ด์šฉํ•œ๋‹ค.

 

๐Ÿ”ธ  Dynamic Programing ์กฐ๊ฑด

  • ์ตœ์  ๋ถ€๋ถ„ ๊ตฌ์กฐ (Optimal Substructure)
    • ๋ถ€๋ถ„ ๋ฌธ์ œ์˜ ์ตœ์  ๊ฒฐ๊ณผ ๊ฐ’์„ ์‚ฌ์šฉํ•ด ์ „์ฒด ๋ฌธ์ œ์˜ ์ตœ์  ๊ฒฐ๊ณผ๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ๋ฅผ ๋งํ•œ๋‹ค.
    • ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์—, ํŠน์ • ๋ฌธ์ œ์˜ ์ •๋‹ต์€ ๋ฌธ์ œ์˜ ํฌ๊ธฐ์™€ ์ƒ๊ด€์—†์ด ๋™์ผํ•˜๋‹ค.
  • ์ค‘๋ณต๋˜๋Š” ๋ถ€๋ถ„ ๋ฌธ์ œ (Overlapping Subproblem)
    • ๋™์ผํ•œ ์ž‘์€ ๋ฌธ์ œ๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ํ•ด๊ฒฐํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ๋งํ•œ๋‹ค.
    • ํ•ด๋‹น ๋ถ€๋ถ„ ๋ฌธ์ œ๊ฐ€ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋‚˜ํƒ€๋‚˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์žฌ์‚ฌ์šฉ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ ๋ถ€๋ถ„ ๋ฌธ์ œ๊ฐ€ ์ค‘๋ณต๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.

 

๐Ÿ” Memoization?

  • DP๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•œ ์ข…๋ฅ˜๋กœ,
  • ํ•œ ๋ฒˆ ๊ตฌํ˜„ํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์— ๋ฉ”๋ชจํ•ด ๋‘๊ณ , ๊ฐ™์€ ์‹์„ ๋‹ค์‹œ ํ˜ธ์ถœํ•˜๋ฉด ๋ฉ”๋ชจํ•œ ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋Œ€๋กœ ๊ฐ€์ ธ์˜ค๋Š” ๊ธฐ๋ฒ•
  • ๊ฐ’์„ ๊ธฐ๋กํ•ด ๋†“๋Š”๋‹ค๋Š” ์ ์—์„œ ์บ์‹ฑ(Caching)์ด๋ผ๊ณ ๋„ ํ•œ๋‹ค.

 

๐Ÿ” ์ตœ์žฅ ๊ณตํ†ต ๋ถ€๋ถ„ ์ˆ˜์—ด(Longest Common Subsequence, LCS)์ด๋ž€ ?

  • LCS๋Š” Longest Common Subsequence์˜ ์•ฝ์ž๋กœ ์ตœ์žฅ ๊ณตํ†ต ๋ถ€๋ถ„ ๋ฌธ์ž์—ด์„ ๋งํ•œ๋‹ค.
  • Subsequence๋Š” ๋ถ€๋ถ„ ์ˆ˜์—ด์ด๋ผ๋Š” ๋œป์œผ๋กœ ์—ฐ์†์ ์ด์ง€ ์•Š์•„๋„ ๋˜๋Š” ๋ฌธ์ž์—ด์ด๋‹ค.
  • ํ•œ๋งˆ๋””๋กœ, ๋‘ ๋ฌธ์ž์—ด์„ ๋น„๊ตํ•  ๋•Œ ๊ณตํ†ต์ ์œผ๋กœ ๋‚˜ํƒ€๋‚˜๋Š” ๋ถ€๋ถ„ ์ˆœ์„œ๋“ค ์ค‘ ๊ฐ€์žฅ ๊ธด ๊ฒƒ์ด๋‹ค.
  • LCS๋Š” ์ตœ์ ํ™”๋ฅผ ํ•ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋™์ ๊ณ„ํš๋ฒ•(DP)์„ ์‚ฌ์šฉํ•ด์•ผ ๊ฐ€์žฅ ํšจ์œจ์ ์œผ๋กœ ๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๐Ÿค” ๋ฌธ์ œ ํ’€์ด

LCS ๋ฌธ์ œ์˜ ๊ฒฝ์šฐ, ๋ถ€๋ถ„ ์ˆ˜์—ด์—์„œ '์ˆœ์„œ'๊ฐ€ ์ง€์ผœ์ง€๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ ๋ฌธ์ž์—ด๋“ค์˜ ๋ฌธ์ž๋“ค์„ ์„œ๋กœ ๋น„๊ตํ•˜๋ฉฐ

๋ฌธ์ž๊ฐ€ ์„œ๋กœ ๊ฐ™์„ ๋•Œ ๊ฐ’์„ 1์”ฉ ์ฆ๊ฐ€์‹œํ‚ค๋ฉด์„œ ๋ˆ„์ ํ•ฉ์„ ๊ตฌํ–ˆ๋‹ค.

 

๋ฌธ์ œ์˜ ์˜ˆ์‹œ๋Œ€๋กœ ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค์–ด ๊ทœ์น™์„ ์ฐพ์•„๋ณด์ž

  • str1 = ACAYKP
  • str2 = CAPCAK 
    A C A Y K P
               
C              
A              
P              
C              
A              
K              

 

str1์˜ ์ฒซ ๋ฒˆ์งธ ๋ฌธ์ž์ธ 'A'๋ฅผ ๊ธฐ์ค€์œผ๋กœ str2์˜ ๋ฌธ์ž๋“ค์„ ๋น„๊ตํ•ด ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

    A C A Y K P
  0 0 0 0 0 0 0
C 0 0          
A 0 1          
P 0 1          
C 0 1          
A 0 1          
K 0 1          

์—ฌ๊ธฐ์„œ ์ž˜ ๊ณ ๋ฏผํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์ด 'A'์™€ 'CAPCA'๋ฅผ ๋น„๊ตํ•  ๋•Œ,

๋‘ ๋ฒˆ์งธ 'A'๊ฐ€ ์˜ค๋”๋ผ๋„ 1์„ ๋”ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ  {C, A, P, C, A}์™€ {A}์˜ ์ตœ์žฅ ๋ถ€๋ถ„ ์ˆ˜์—ด์€ {A} ํ•˜๋‚˜๋ฟ์ด๋ฏ€๋กœ 1์ด ๋œ๋‹ค.

 

    A C A Y K P
  0 0 0 0 0 0 0
C 0 0 1        
A 0 1 1        
P 0 1 1        
C 0 1 2        
A 0 1 2        
K 0 1 2        

{C}์™€ {A, C}์˜ ๋ถ€๋ถ„ ์ˆ˜์—ด์€ {C}์ด๊ณ ,

{C, A, P, C}์™€ {A, C}์˜ ๋ถ€๋ถ„ ์ˆ˜์—ด์€ {A, C}๋กœ +1์ด ์ฆ๊ฐ€ํ•œ๋‹ค.

์ด๋•Œ, {A, C}์˜ ์ˆœ์„œ๋„ ๊ณ ๋ คํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ {C, A}๋Š” ํ•ด๋‹น ๋ถ€๋ถ„์˜ ์ˆ˜์—ด์ด ๋  ์ˆ˜ ์—†๋‹ค.

 

์ด๋Ÿฌํ•œ ๊ทœ์น™์„ ํ†ตํ•ด, ํ‘œ๋ฅผ ๋ชจ๋‘ ์ฑ„์šฐ๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

    A C A Y K P
  0 0 0 0 0 0 0
C 0 0 1 1 1 1 1
A 0 1 1 2 2 2 2
P 0 1 1 2 2 2 3
C 0 1 2 2 2 2 3
A 0 1 2 3 3 3 3
K 0 1 2 3 3 4 4

ํ‘œ๋ฅผ ์ฑ„์šฐ๋‹ค ๋ณด๋ฉด ๊ทœ์น™์„ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.

 

๊ฐ ์—ด์„ ์ฑ„์›Œ๋‚˜๊ฐˆ ๋•Œ, ์ž์‹ ๊ณผ ๊ฐ™์€ ๋ฌธ์ž๊ฐ€ ์žˆ๋‹ค๋ฉด +1, ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด ์ด์ „ ํ–‰์˜ ์›์†Œ ๋˜๋Š” ์—ด์˜ ์›์†Œ ์ค‘ ํฐ ๊ฐ’์„ ๊ธฐ์ค€์œผ๋กœ ์ฑ„์šฐ๋ฉด ๋œ๋‹ค.

 

๊ทธ๋Ÿฐ๋ฐ, ๊ฐ™์€ ๋ฌธ์ž๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ ์–ด๋–ค ์ˆ˜๋ฅผ +1ํ•ด์•ผ ํ• ๊นŒ

 

์•„๋ž˜ ์˜ˆ์‹œ๋ฅผ ๋“ค์–ด๋ณด์ž

(0, 1)์„ ๋ณธ๋‹ค๋ฉด {C}์™€ {A, C}์˜ ๊ณตํ†ต๋ถ„๋ชจ์ธ 'C'๋ฅผ ์˜๋ฏธํ•˜๋ฉฐ 1์˜ ๊ฐ’์ด ๋“ค์–ด์˜จ๋‹ค.

(1, 2)๋ฅผ ๋ณธ๋‹ค๋ฉด {C, A}์™€ {A, C, A}์˜ ๊ณตํ†ต ์ˆ˜์—ด์ธ {C, A}๊ฐ€ ๋˜์–ด 2์˜ ๊ฐ’์ด ๋“ค์–ด์˜จ๋‹ค.

 

์ฆ‰, {C}์™€ {A, C}์—์„œ 'A'๋ผ๋Š” ๊ณตํ†ต ์›์†Œ๊ฐ€ ์ถ”๊ฐ€๋œ ๊ฒƒ์ด๋‹ค.

์ •๋ฆฌํ•˜๋ฉด i๋ฒˆ์งธ ์›์†Œ์™€ j๋ฒˆ์งธ ์›์†Œ๊ฐ€ ๊ฐ™๋‹ค๋ฉด (i-1, j-1)์˜ LCS ๊ธธ์ด์˜ +1์ด ๋œ๋‹ค.

 

์ด๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

 

โœ” ์ตœ์ข… ์ฝ”๋“œ

 ๋ฉ”๋ชจ๋ฆฌ : 15828KB 
 ์‹œ๊ฐ„ : 96ms
import java.io.*;

public class Main {
    static char[] str1, str2;
    static int[][] dp;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        // ๋‘ ๋ฌธ์ž์—ด ์ž…๋ ฅ
        str1 = br.readLine().toCharArray();
        str2 = br.readLine().toCharArray();

        bw.append(lcs(str1.length, str2.length) + "\n");
        bw.flush();
        bw.close();
        br.close();
    }

    private static int lcs(int a, int b) {
        dp = new int[a+1][b+1];
        for (int i = 1; i <= a; i++) {
            for (int j = 1; j <= b; j++) {
                // ๊ฐ™์€ ๋ฌธ์ž๊ฐ€ ๋“ค์–ด์˜จ๋‹ค๋ฉด
                // ๋ชจ๋“  ์ˆ˜์—ด์— ๊ฐ™์€ ๋ฌธ์ž๊ฐ€ ์ถ”๊ฐ€๋˜๋Š” ๊ฒฝ์šฐ
                // ๊ทธ๋Ÿฌ๋ฏ€๋กœ ๋Œ€๊ฐ์„ ์— ์žˆ๋Š” ๊ฐ’์— +1
                if (str1[i-1] == str2[j-1]) dp[i][j] = dp[i-1][j-1] + 1;
                // ๋‹ค๋ฅธ ๋ฌธ์ž๊ฐ€ ๋“ค์–ด์˜ค๋Š” ๊ฒฝ์šฐ
                // ์ด์ „ ์—ด์˜ ๊ฐ’๊ณผ ์ด์ „ ํ–‰์˜ ๊ฐ’ ์ค‘ ๋” ํฐ ๊ฐ’์„ ๊ฐ€์ ธ์˜ด
                else dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
            }
        }
        return dp[a][b];
    }
}

 

 

 

 

 

๐Ÿ“ƒ reference