https://www.acmicpc.net/problem/9251
9251번: LCS
LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다. 예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.
www.acmicpc.net
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
import java.io.*;
import java.util.*;
import static java.lang.Math.max;
public class Main {
public static int lcs[][];
public static String []arr1;
public static String []arr2;
public static void main(String[]args) throws IOException {
Scanner sc=new Scanner(System.in);
String []arr1=sc.next().split("");
String[]arr2=sc.next().split("");
//두 문자열의 크기가 다를 수 있다!
lcs=new int[arr1.length+1][arr2.length+1];
for(int i=0;i<=arr1.length;i++){
lcs[i][0]=0;
}
for(int i=0;i<=arr2.length;i++){
lcs[0][i]=0;
}
for(int i=1;i<= arr1.length;i++){
for(int j=1;j<=arr2.length;j++){
if(arr1[i-1].equals(arr2[j-1])){
lcs[i][j]=lcs[i-1][j-1]+1;
}else{
lcs[i][j]=max(lcs[i-1][j],lcs[i][j-1]);
}
}
}
System.out.println(lcs[arr1.length][arr2.length]);
}
}
|
cs |
런타임에러가 자꾸 났는데 이유는 두 문자열의 크기가 다를 수 있기 때문이다. 그래서 첫번째 문자열의 크기를 행의 길이, 두번째 문자열의 크기를 열의 길이로 두고 따로따로 설정해주는 것이 가장 좋다!
LCS알고리즘을 이용하면 된다.
[알고리즘] 그림으로 알아보는 LCS 알고리즘 - Longest Common Substring와 Longest Common Subsequence
LCS는 주로 최장 공통 부분수열(Longest Common Subsequence)을 말합니다만, 최장 공통 문자열(Longest Common Substring)을 말하기도 합니다.
velog.io
이 글에서 LCS를 엄청 잘 설명해주셨다. 나도 이걸 보고 이해를 했다.
ACAYKP 와 CAPCAK의 최장공통부분 수열을 찾으면 되는데
우선 A를 기준으로 살펴보자
A와 C -> 공통부분이 0이다.
A와 CA -> 공통부분이 1
A와 CAP ->1
A와 CAPC ->1
A와 CAPCA ->1
A와 CAPCAKS ->1
이번에는 C를 기준으로 볼건데, 수열이기 때문에 AC가 된다.
이게 무슨 말이냐면
AC와 C 비교 ->공통부분 C로 1
AC와 CA -> 공통부분 1 (A또는 C)
AC와 CAP ->1
AC와 CAPC -> 2(AC)
AC와 CAPCA -> 2 (AC)
AC와 CAPCAK -> 2
3번째 인덱스인 A가 기준이 됐을 때도 마찬가지이다. 이번에는 수열이 ACA가 되는데
ACA 와 C ->1
ACA와 CA ->2
ACA와 CAP ->2
ACA와 CAPC ->2 (AC)
ACA와 CAPCA ->3(ACA)
ACA와 CAPCAK ->3(ACA)
마지막 인덱스인 P가 기준일때를 한번 더 보자
ACAYKP 와 C -> 1(C)
ACAYKP 와 CA ->2(CA)
ACAYKP와 CAP ->3(CAP)
ACAYKP와 CAPC ->3(CAP)
ACAYKP와 CAPCA -> 3(CAP또는 ACA)
ACAYKP와 CAPCAK ->4 (ACAK)
결론적으로 두 문자가 같으면 LCS[i][j]에 LCS[i-1][j-1]+1을 넣어주면 되고
두 문자가 다르면 이전 행(LCS[i-1][j]) 과 이전 열(LCS[i][j-1]) 중 더 큰 값을 LCS[i][j]에 넣어주면 된다!
이걸 좀 더 설명하자면
예를 들어 ACA와 CAP 문자열을 비교하는데
A C A
C
A
P
2행 3열은 ACA와 CA를 비교한 것이기에 공통 수열이 2이고
3행 2열은 CAP와 AC를 비교한 것이기에 공통 수열이 1이다.
두 문자열 모두 3번째 인덱스인 A와 P가 서로 다르기에 lcs[i-1][j-1]+1을 하는 것이 아닌
2행 3열과 3행 2열 중 더 큰 수열 값이 3행 3열로 들어오게 된다. 그래야 3행 3열에 최장 수열을 넣을 수 있기 때문이다. 둘 중 최장 수열은 2가 된다!
또 다른 예로는 3행 3열의 값이 같은 ACA BAA를 봐보자.
A C A
B
A
A
2행 2열은 AC와 BA의 비교이기 때문에 최장공통 수열은 1이 된다. 여기서 둘 다 똑같이 A가 뒤에 오기 때문에 최장공통수열인 1에 1을 더한 2가 된다. 이걸 일반화 하면 LCS[i][j]=LCS[i-1][j-1]+1이 나온다!
도움을 받은 글
https://st-lab.tistory.com/139
[백준] 9251번 : LCS - JAVA [자바]
www.acmicpc.net/problem/9251 9251번: LCS LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다. 예를 들어, ACAY..
st-lab.tistory.com
'알고리즘 > DP' 카테고리의 다른 글
[java 백준] 골드 5/13398번 연속합2 (0) | 2022.05.04 |
---|---|
[java 백준] 골드 5/ 4811번 알약 (0) | 2022.05.01 |
[java 백준] 골드 5/ 2565번 전깃줄 (0) | 2022.04.09 |
[C++백준] 실버 1 / 1932번 정수 삼각형 (0) | 2022.02.28 |
[C++ 백준]실버 5/1010번 다리놓기 (0) | 2022.02.12 |
댓글