문제 설명
주어진 배열에서 가장 긴 증가하는 부분 수열의 길이를 찾는 문제를 해결해 보겠습니다. 증가하는 부분 수열은 배열에서 서로 다른 인덱스를 가지는 요소들 중에서, 해당 요소들이 오름차순으로 정렬된 부분 배열입니다. 예를 들어, 배열 [10, 22, 9, 33, 21, 50, 41, 60, 80]
에 대해 가장 긴 증가하는 부분 수열은 [10, 22, 33, 50, 60, 80]
로 길이는 6입니다.
문제 정의
주어진 정수 배열 arr
이 있을 때, 가장 긴 증가하는 부분 수열의 길이를 반환하는 메서드를 작성하시오.
입력
- 첫 번째 줄에 배열의 길이
n
이 주어집니다. (1 ≤ n ≤ 1000) - 두 번째 줄에
n
개의 정수가 주어집니다. 각 정수는-10^6 ≤ arr[i] ≤ 10^6
입니다.
출력
가장 긴 증가하는 부분 수열의 길이를 출력합니다.
예제
입력
9
10 22 9 33 21 50 41 60 80
출력
6
문제 풀이 방법
가장 긴 증가하는 부분 수열을 찾는 여러 알고리즘 중 가장 많이 사용되는 방법은 동적 프로그래밍(Dynamic Programming)입니다. 이 방법은 문제를 작은 부분 문제로 나누어 해결하고, 이 결과를 바탕으로 전체 문제를 해결하는 접근법입니다.
단계별 설명
- 배열 초기화: 주어진 배열
arr
의 길이를n
이라 가정합니다. 동적 프로그래밍 배열dp
를 초기화하여 각 인덱스i
에 대해, 그 인덱스까지의 가장 긴 증가하는 부분 수열의 길이를 저장할 것입니다. 우선 각 요소가 자기 자신만으로도 수열이 될 수 있으므로 초기값을 1로 설정합니다. - 이중 반복문: 중첩 반복문을 사용하여 모든 쌍의 인덱스
i
와j
를 비교합니다. 이때i
는j
보다 크고,arr[i]
가arr[j]
보다 클 경우 (즉, 증가하는 조건을 만족하는 경우),dp[i]
값을 업데이트합니다. 구체적으로,dp[i] = max(dp[i], dp[j] + 1)
로 설정합니다. 이것은j
를 포함한 수열의 길이에 1을 추가하는 것입니다. - 최대 길이 찾기: 모든 수열 길이를 계산한 후
dp
배열에서 최대값을 찾아 반환합니다.
C# 구현
using System;
class Program
{
static void Main()
{
int n = int.Parse(Console.ReadLine());
int[] arr = Array.ConvertAll(Console.ReadLine().Split(' '), int.Parse);
int[] dp = new int[n];
for (int i = 0; i < n; i++)
{
dp[i] = 1; // 각 요소는 최소 1개의 수열을 형성할 수 있음
}
for (int i = 1; i < n; i++)
{
for (int j = 0; j < i; j++)
{
if (arr[i] > arr[j] && dp[i] < dp[j] + 1)
{
dp[i] = dp[j] + 1;
}
}
}
int maxLength = dp[0];
for (int i = 1; i < n; i++)
{
if (dp[i] > maxLength)
{
maxLength = dp[i];
}
}
Console.WriteLine(maxLength);
}
}
시간 복잡도
이 알고리즘의 시간 복잡도는 O(n^2)
입니다. 이는 두 개의 중첩 반복문을 사용하기 때문입니다. 외부 반복문과 내부 반복문 모두 각각 배열의 길이만큼 실행되므로 최악의 경우 총 n * n
의 연산이 필요합니다. 공간 복잡도는 O(n)
이며, 이는 dp
배열을 저장하기 위해 필요한 공간입니다.
결론
이번 강좌에서는 가장 긴 증가하는 부분 수열을 찾는 알고리즘을 C#으로 구현해 보았습니다. 이 문제는 코딩 테스트에서 자주 출제되며, 동적 프로그래밍의 기초를 배우고 익히는 데 매우 유용합니다. 꾸준한 연습을 통해 다양한 문제를 해결하는 데 필요한 사고력과 접근 방식을 기를 수 있습니다.