알고리즘-이론
LCS(최장 공통 부분 수열)
절박한개발자
2024. 11. 10. 16:18
최장 공통부분 수열이란?
주어진 두 문자열 사이에서 순서는 같지만 연속적일 필요는 없는 가장 긴 공통부분 수열을 찾는 문제이다.
즉, 두개의 문자열이 공통된 순서대로 존재하는지를 확인하는 알고리즘이다.
사용하는 이유
기존 반복문을 사용해 문자열 X와 Y의 모든 부분 수열을 찾으려면 각각 O(2^m)과 O(2^n)의 연산이 필요하며,
이 경우 전체 시간복잡도는 O(4^n)으로 매우 오래 걸린다.
하지만 LCS(Longest Common Subsequence) 알고리즘을 사용하면 문제를 O(m * n)의 시간복잡도로 해결이 가능하다.
접근방법(탑다운)
1. 포인터를 사용해서 문제 해결
문자열 A의 포인터 aIndex, 문자열 B의 포인터 bIndex를 사용하며 이동하면서 문자열을 비교한다.
2. 문자열 비교
- A [aIndex]와 B [bIndex]가가 같은 문자라면:
- 해당 위치는 공통부분 수열의 일부이므로 LCS(i-1, j-1) + 1의 결과를 사용.
- 두 포인터를 모두 하나씩 줄여 재귀적으로 다음 위치를 비교합니다.
- A[aIndex]와 B[bIndex]가 다른 문자라면:
- LCS(aIndex-1, bIndex): A의 포인터만 줄이는 경우
- LCS(aIndex, bIndex-1): B의 포인터만 줄이는 경우두 가지 경우를 고려해 더 큰 값만 취합니다.
- 이 중 최대값을 선택해 부분 문제의 최적 해를 찾으면 정답이다.
알고리즘 실전
코드트리 | 코딩테스트 준비를 위한 알고리즘 정석
국가대표가 만든 코딩 공부의 가이드북 코딩 왕초보부터 꿈의 직장 코테 합격까지, 국가대표가 엄선한 커리큘럼으로 준비해보세요.
www.codetree.ai
import java.util.*;
import java.io.*;
public class Main {
static String A,B;
static int[][] dp;
public static void main(String[] args) throws IOException{
simulate();
}
private static void simulate() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
A = br.readLine();
B = br.readLine();
//A의 문자열 길이, B의 문자열길이
dp = new int[A.length()][B.length()];
for(int i = 0; i < A.length(); i++) {
Arrays.fill(dp[i],-1);
}
int result = dfs(A.length()-1,B.length()-1);
System.out.println(result);
}
private static int dfs(int aIndex, int bIndex) {
if(aIndex <0 || bIndex<0) {
return 0;
}
if(dp[aIndex][bIndex]!=-1) {
return dp[aIndex][bIndex];
}
dp[aIndex][bIndex] = 0;
char aCh = A.charAt(aIndex);
char bCh = B.charAt(bIndex);
// 같은경우
if(aCh == bCh) {
int result = dfs(aIndex-1,bIndex-1);
dp[aIndex][bIndex] = Math.max(dp[aIndex][bIndex],result+1);
}else { // 다른경우
int left = dfs(aIndex-1,bIndex);
int right = dfs(aIndex,bIndex-1);
int max = Math.max(left,right);
dp[aIndex][bIndex] = Math.max(dp[aIndex][bIndex],max);
}
return dp[aIndex][bIndex];
}
}