tgool
Tgool
tgool
전체 방문자
오늘
어제
  • 분류 전체보기
    • Data Science
      • AI
      • Data Mining
      • ML(Machine Learning)
    • Computer Science
      • 자료구조
      • 알고리즘
      • 시스템 프로그래밍
      • 운영체제
      • 컴퓨터 구조
      • 컴퓨터 네트워크
      • 데이터 베이스
      • 파이썬
      • 자바
      • 아두이노
    • Math
      • 통계학
      • 확률론
      • 선형대수학
      • 수리통계학
      • 회귀분석
    • TOFEL
    • Git
    • Plan
    • Book
    • Working out
      • 영양과 생활
      • 운동 정보
      • 운동 기록

인기 글

최근 글

최근 댓글

hELLO · Designed By 정상우.
tgool

Tgool

Computer Science/알고리즘

[백준] 9251번: LCS_JAVA

2023. 1. 25. 18:07

문제 (https://www.acmicpc.net/problem/9251)

 

문제

 

 

LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다.

예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.

 

입력

첫째 줄과 둘째 줄에 두 문자열이 주어진다. 문자열은 알파벳 대문자로만 이루어져 있으며, 최대 1000글자로 이루어져 있다.

 

출력

첫째 줄에 입력으로 주어진 두 문자열의 LCS의 길이를 출력한다.

 

예제 입력 1 

ACAYKP
CAPCAK

예제 출력 1

4

풀이

 

- LCS(Longest Common Subsequence, 최장 공통 부분 수열)란 공통된 가장 긴 부분 수열이다. 즉 임의의 두 수열이 주어졌을 때, 각각의 부분 수열 중 서로 같은 부분 수열 중에서 길이가 가장 긴 부분 수열을 뜻한다. 

 

- 부분 수열은 순서를 가진다. (부분 집합이 아니다)

 

- ACAYKP의 부분 수열은 {A}, {C}, {A}, {Y}, {K}, {P}, {A,C}, ... ,{A,C,A,Y,K,P} 이고

  CAPCAK의 부분 수열은 {C}, {A}, {P}, {C}, {A}, {K}, {C,A}, ... , {C,A,P,C,A,K} 이다.

 

- 서로 같은 부분 수열은 {A}, {C}, {C,A}, ... ,{A,C,A}, ... ,{A,C,A,K}가 있는데 이 중 LCS는 {A,C,A,K}가 된다.

   ACAYKP

   CAPCAK

 

- 아래와 같이 2차원 배열을(표) 이용해서 문제를  해결 해보자. (규칙 찾기)

 

- 아래의 표는 배열이 깊어질수록 문자가 추가되어 부분 수열을 구성하고 표 안에 들어가는 원소(정수 값)는 LCS 길이, 즉 공통 부분 수열의 최대 길이를 뜻한다.

  A: {A}의 부분수열 C: {A,C}의 부분수열 A Y K P: {A,C,A,Y,K,P}의 부분수열
C: {C}의 부분수열            
A: {C,A}의 부분수열            
P            
C            
A            
K: {C,A,P,C,A,K}의 부분수열            

- 글로 설명하는 거보다 예시를 보며 규칙을 찾는 것이 빠르다. 

  A: {A}의 부분수열 C: {A,C}의 부분수열 A Y K P: {A,C,A,Y,K}의 부분수열
C: {C}의 부분수열 0          
A: {C,A}의 부분수열 1          
P 1          
C 1          
A 1          
K: {C,A,P,C,A}의 부분수열 1          

 

- 위 표를 보면 {C,A}의 부분 수열과 {A}의 부분 수열 중 LCS는 {A}이므로 길이는 1이다. 

 

  A: {A}의 부분수열 C: {A,C}의 부분수열 A Y K P: {A,C,A,Y,K}의 부분수열
C: {C}의 부분수열 0 1        
A: {C,A}의 부분수열 1 1        
P 1 1        
C 1 2        
A 1 2        
K: {C,A,P,C,A}의 부분수열 1 2        

- 위 표를 보면 {C,A,P,C} 의 부분 수열 중 {A,C}와 {A,C}의 부분 수열 중 {A,C}가 LCS이므로 길이는 2가 된다.

 

- 이런 식으로 반복하여 표를 완성시키며 규칙을 찾아본다. 

 

  A: {A}의 부분수열 C: {A,C}의 부분수열 A Y K P: {A,C,A,Y,K}의 부분수열
C: {C}의 부분수열 0 1 1 1 1 1
A: {C,A}의 부분수열 1 1 2 2 2 2
P 1 1 2 2 2 3
C 1 2 2 2 2 3
A 1 2 3 3 3 3
K: {C,A,P,C,A}의 부분수열 1 2 3 3 4 4

- 규칙을 찾았는가?

 

- X번째 원소와 Y번째 원소가 같으면, 해당 칸은 (X-1, Y-1)의 원소 + 1이 된다.

 

- 왜 (X-1, Y-1)의 원소 + 1 이나면, 위 예시에서 1열을 보면 A가 2번째 만나는 경우 이전 행에 + 1할 경우 규칙에 어긋난다. 

 

- X번째 원소와 Y번째 원소가 같지 않으면, 해당 칸은 이전 행의 원소 또는 열 원소 중 큰 것을 채우면 된다. (MAX 함수를 이용하면 되겠쥬?)

 

- 공집합일 경우도 존재하기 때문에, 실제로 코드로 구현할 때는 공집합을 포함해야 한다.

  공집합 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

 

- 2차원 배열과 반복문을 이용해서 위 과정을 코드로 구현해보자. 

 

- 위 과정만 떠올릴 수 있다면, 생각보다 간단하다.

 

 


코드

public static void main(String[] args) {
 
		Scanner scan = new Scanner(System.in);
		
		char[] str1 = scan.nextLine().toCharArray();
		char[] str2 = scan.nextLine().toCharArray();
		
		//공집합 표현을 위해 인덱스가 한 줄씩 추가, 0으로 초기화 되어 있음.
		int[][] result = new int[str1.length + 1][str2.length + 1];
		
		//1부터 시작, index 0 은 공집합이므로 0으로 초기화 되어 있음.  
		for(int i = 1; i <= str1.length; i++) {
			for(int j = 1; j <= str2.length; j++) {
				
				//(i-1)과 (j-1) 번째 문자가 서로 같은 경우  
				if(str1[i - 1] == str2[j - 1]) {
					//대각선 위 (i-1, j-1)의 result에 +1 한 값으로 대입
					result[i][j] = result[i - 1][j - 1] + 1;	
				}
				
				//같지 않다면 이전 열(i-1)과 이전 행(j-1)의 값 중 큰 값으로 대입
				else {
					result[i][j] = Math.max(result[i - 1][j], result[i][j - 1]);
				}
			}
		}
        
		//마지막 인덱스의 값이 주어진 문자열의 LCS 길이가 된다.
		System.out.println(result[str1.length][str2.length]);
		scan.close();
	}

'Computer Science > 알고리즘' 카테고리의 다른 글

[백준] 4963번: 섬의 개수_JAVA  (0) 2023.02.13
[백준] 1182번: 부분수열의 합_JAVA  (0) 2023.02.06
[백준] 1018번: 체스판 다시 칠하기_JAVA  (0) 2023.02.06
[백준] 5525번: IOIOI_JAVA  (0) 2023.01.25
[백준] 1652번: 누울 자리를 찾아라_JAVA  (1) 2023.01.25
    'Computer Science/알고리즘' 카테고리의 다른 글
    • [백준] 1182번: 부분수열의 합_JAVA
    • [백준] 1018번: 체스판 다시 칠하기_JAVA
    • [백준] 5525번: IOIOI_JAVA
    • [백준] 1652번: 누울 자리를 찾아라_JAVA
    tgool
    tgool

    티스토리툴바