백준 9252 LCS 2 [자바]

baekjoon 9252 LCS 2

java

문제 분석

  • 두 문자열이 주어진다. 문자열은 대문자로만 이루어져 있다.
  • 두 문잘열의 최장 공통 부분 수열을 구하고, 그 길이와 문자열을 나타내어라.

입력조건

String 문자열1
String 문자열2

풀이과정

  • dp
  • 각 문자열의 각 위치까지 최대인 공통 부분 수열을 계산하면서, 끝까지 진행.

  • 최초에 풀이를 진행할 때는 element라는 하나의 클래스를 만들어, 그 안에 현재 공통 부분 수열의 길이와, 그 문자열을 저장하였다.
  • 하지만 이렇게 진행하니 시간초과가 발생하였다.
  • 예상되는 원인으로는 1000*1000 사이즈의 문자열 배열을 계속 복사하니, 0.4초는 턱없이 부족했다고 생각한다.

  • 그래서, element 클래스를 날리고, 2차원 int 배열로 최장 공통 부분 수열의 길이만 저장하였고,
  • 이를 끝낸 후, 맨 끝에서부터 추적해서 올라가면서 정답 문자열을 만들었다.

  • 아래는 문제풀면서 그렸던 그림이다…

코드 구성

  • dp로 LCS 크기 저장하기

    for(int aidx = 1; aidx <= alen; aidx++) {
        for(int bidx = 1; bidx <= blen; bidx++) {
            if (a.charAt(aidx-1) == b.charAt(bidx-1)) map[aidx][bidx] = map[aidx-1][bidx-1] + 1;
            else map[aidx][bidx] = Math.max(map[aidx-1][bidx], map[aidx][bidx-1]);
        }
    }
    // dp 끝
    System.out.println(map[alen][blen]);
    
  • 정답 문자열 찾기

    StringBuilder ans = new StringBuilder();
    while(alen > 0 && blen > 0) {
        if(a.charAt(alen-1) == b.charAt(blen-1)) {
            ans.append(a.charAt(alen-1));
            alen--;
            blen--;
        }
        else {
            if(map[alen-1][blen] > map[alen][blen-1]) 
                alen--;
            else blen--;
        }
    }
    

전체 코드

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

public class BJ9252_LCS2 {
	public static void main(String[] args) throws IOException, CloneNotSupportedException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String a = br.readLine();
		String b = br.readLine();
		
		int alen = a.length();
		int blen = b.length();
		int[][] map = new int[alen+1][blen+1];
		
		for(int aidx = 1; aidx <= alen; aidx++) {
			for(int bidx = 1; bidx <= blen; bidx++) {
				if (a.charAt(aidx-1) == b.charAt(bidx-1)) map[aidx][bidx] = map[aidx-1][bidx-1] + 1;
				else map[aidx][bidx] = Math.max(map[aidx-1][bidx], map[aidx][bidx-1]);
			}
		}
		// dp 끝
		System.out.println(map[alen][blen]);
		
		// 디버그
//		for(int i = 1; i <= alen; i++) {
//			for(int j = 1; j <= blen; j++) {
//				System.out.print(map[i][j] + " ");
//			}
//			System.out.println();
//		}
		
		StringBuilder ans = new StringBuilder();
		while(alen > 0 && blen > 0) {
			if(a.charAt(alen-1) == b.charAt(blen-1)) {
				ans.append(a.charAt(alen-1));
				alen--;
				blen--;
			}
			else {
				if(map[alen-1][blen] > map[alen][blen-1]) 
					 alen--;
				else blen--;
			}
		}
		if(!ans.equals("")) System.out.print(ans.reverse());
	}
}

PS

시간초과를 받은 코드

package ChangHangeol;

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

public class BJ9252_LCS2 {
	static class element implements Cloneable {
		int len;
		String data;
		element(int len, String data){
			this.len = len;
			this.data = data;
		}
		@Override
		protected element clone() throws CloneNotSupportedException {
			return (element) super.clone();
		}
	}
	public static void main(String[] args) throws IOException, CloneNotSupportedException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String a = br.readLine();
		String b = br.readLine();
		
		int alen = a.length();
		int blen = b.length();
		
		element[][] map = new element[alen+1][blen+1];
		for(int i = 0; i <= blen; i++) map[0][i] = new element(0, "");
		for(int i = 0; i <= alen; i++) map[i][0] = new element(0, "");
		
		for(int aidx = 1; aidx <= alen; aidx++) {
			for(int bidx = 1; bidx <= blen; bidx++) {
				element idf1 = map[aidx][bidx-1];
				element idf2 = map[aidx-1][bidx];

				if(idf1.len > idf2.len) map[aidx][bidx] = idf1.clone();
				else					map[aidx][bidx] = idf2.clone();
				
				if(a.charAt(aidx-1) == b.charAt(bidx-1)) {
					element idf = map[aidx-1][bidx-1];
					if (map[aidx][bidx].len < idf.len + 1)
						map[aidx][bidx] = new element(idf.len + 1, String.format(idf.data + b.charAt(bidx-1)));
				}
			}
		}
		element f = map[alen][blen];
		System.out.println(f.len + "\n" + f.data);
	}
}