C# 코딩테스트 강좌, 최장 공통 부분 수열 찾기

문제 설명

주어진 두 문자열 A와 B가 있을 때, 이들 문자열의 최장 공통 부분 수열(Longest Common Subsequence, LCS)을 찾는 문제입니다. 부분 수열은 문자열에서 문자의 순서를 유지하면서 삭제로 얻을 수 있는 문자열입니다. 즉, A의 부분 수열이 B에 존재해야 합니다.

예를 들어, 문자열 A가 “ABCBDAB”이고 B가 “BDCAB”라면, 최장 공통 부분 수열은 “BCAB”입니다. 이러한 LCS 문제는 다양한 분야에서 효율적인 알고리즘을 필요로 하는 문제입니다.

문제 입력

두 문자열 A와 B의 길이 N, M (1 ≤ N, M ≤ 1000) 및 문자열 A와 B가 주어집니다.

문제 출력

최장 공통 부분 수열의 길이를 출력합니다.

문제 해결 과정

1. 동적 프로그래밍 이해

이 문제는 동적 프로그래밍(DP)을 사용하여 해결할 수 있습니다. DP는 복잡한 문제를 작은 부분 문제로 나누어 해결하여 효율성을 높이는 기법입니다. 이 경우, DP 배열을 사용하여 각 문자 쌍 간의 LCS 길이를 저장하고 계산합니다.

2. DP 배열 초기화

우선, 두 문자열 A와 B의 길이에 따라 2차원 DP 배열을 초기화합니다. DP[i][j]는 A의 첫 i개 문자와 B의 첫 j개 문자의 최장 공통 부분 수열의 길이를 나타냅니다.


    int[,] dp = new int[N + 1, M + 1];
    

3. DP 상태 전이

DP 규칙은 다음과 같습니다:

  • 만약 A의 i번째 문자와 B의 j번째 문자가 같으면: dp[i][j] = dp[i - 1][j - 1] + 1
  • 만약 A의 i번째 문자와 B의 j번째 문자가 다르면: dp[i][j] = Math.Max(dp[i - 1][j], dp[i][j - 1])

4. 최종 결과

DP 배열이 채워진 후, dp[N][M]에는 최장 공통 부분 수열의 길이가 저장됩니다.

코드 구현


    using System;

    class Program
    {
        static void Main(string[] args)
        {
            string A = "ABCBDAB";
            string B = "BDCAB";
            int N = A.Length;
            int M = B.Length;

            int[,] dp = new int[N + 1, M + 1];

            for (int i = 1; i <= N; i++)
            {
                for (int j = 1; j <= M; j++)
                {
                    if (A[i - 1] == B[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]);
                    }
                }
            }

            Console.WriteLine("최장 공통 부분 수열의 길이: " + dp[N, M]);
        }
    }
    

테스트 케이스

예제 입력


    A: ABCBDAB
    B: BDCAB
    

예제 출력


    최장 공통 부분 수열의 길이: 4
    

시간 복잡도 분석

이 동적 프로그래밍 알고리즘의 시간 복잡도는 O(N * M)이며, 공간 복잡도 또한 O(N * M)입니다. 이를 통해 두 문자열의 길이가 1000일 때도 충분히 성능을 만족하는 알고리즘입니다.

결론

최장 공통 부분 수열(LCS) 문제는 컴퓨터 과학의 여러 분야에서 어떻게 알 수 있는지를 보여주는 주요 문제입니다. 동적 프로그래밍을 사용하여 효율적으로 해결할 수 있음을 확인했습니다. 이 방법은 실제 코딩테스트에서 수시로 등장하므로, 잘 이해하고 연습하는 것이 중요합니다.