티스토리 뷰
728x90
LIS(Longest Increasing Subsequence )
개념
- 주어진 배열에서 가장 긴 증가하는 부분 수열의 길이를 구하는 코드. DP 방식이나 이분 탐색을 이용하여 풀 수 있다. 예를 들어, 배열 [10, 20, 10, 30, 20, 50]가 주어졌을 때, 가장 긴 증가하는 부분 수열은 [10, 20, 30, 50]로 길이는 4가 된다.
- 문제 풀이 방식
- 동적 프로그래밍(DP) 방식 - 시간 복잡도: O(n^2)
- 이분 탐색을 이용한 최적화 방식 - 시간 복잡도: O(n log n)
풀이 방식(DP)
- 배열을 순서대로 탐색하면서 dp 배열을 갱신해나가는 방식. 각 위치에서 해당 위치까지의 가장 긴 증가하는 부분 수열의 길이를 저장한다.
- 점화식: dp[i]는 i번째 요소까지의 가장 긴 증가하는 부분 수열의 길이
- 갱신 방법: 현재 위치 i보다 앞에 있는 모든 위치 j에 대해 arr[i] > arr[j]이면, dp[i] = max(dp[i], dp[j] + 1)로 갱신한다.
풀이 방식(이분 탐색)
- dp 배열을 이용해 현재까지의 LIS를 유지하면서, 각 요소가 들어갈 위치를 이분 탐색으로 찾아 대체하는 방식. 이때 dp 배열에 포함된 요소는 LIS의 길이에만 관여하고, 실제 수열을 구성하지는 않는다.
- 풀이 과정:
- dp 배열을 빈 배열로 초기화한다.
- 배열의 각 요소에 대해, dp 배열 내에서 그 요소의 위치를 이분 탐색으로 찾는다.
- 이분 탐색의 결과 위치에 해당 요소를 삽입하거나 대체하여 dp 배열을 갱신한다.
- 최종적으로 dp 배열의 길이가 가장 긴 증가하는 부분 수열의 길이가 된다.
예제 코드
DP
# 파이썬
def lis_dp(arr):
n = len(arr)
dp = [1] * n # 각 위치에서 최소 길이는 1로 시작
for i in range(1, n):
for j in range(i):
if arr[i] > arr[j]: # 증가하는 부분 수열 조건
dp[i] = max(dp[i], dp[j] + 1) # 가장 긴 길이 갱신
return max(dp) # dp 배열에서 최댓값이 가장 긴 부분 수열 길이
// java
import java.util.Arrays;
public class LIS_DP {
public static int lisDP(int[] arr) {
int n = arr.length;
int[] dp = new int[n];
Arrays.fill(dp, 1); // 각 위치에서 최소 길이는 1로 시작
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (arr[i] > arr[j]) { // 증가하는 부분 수열 조건
dp[i] = Math.max(dp[i], dp[j] + 1); // 가장 긴 길이 갱신
}
}
}
int maxLength = 0;
for (int length : dp) {
maxLength = Math.max(maxLength, length);
}
return maxLength; // 가장 긴 부분 수열의 길이 반환
}
public static void main(String[] args) {
int[] arr = {10, 20, 10, 30, 20, 50};
System.out.println("DP 방식 LIS 길이: " + lisDP(arr)); // 출력: 4
}
}
이분 탐색
# 파이썬
from bisect import bisect_left
def lis_binary_search(arr):
dp = [] # LIS 배열을 유지하는 dp 리스트
for num in arr:
pos = bisect_left(dp, num) # num이 들어갈 위치를 이분 탐색으로 찾음
if pos == len(dp):
dp.append(num) # num이 가장 큰 값이면 추가
else:
dp[pos] = num # num이 들어갈 위치에 대체
return len(dp) # dp 배열의 길이가 LIS 길이
// java
import java.util.ArrayList;
import java.util.Collections;
public class LIS_BinarySearch {
public static int lisBinarySearch(int[] arr) {
ArrayList<Integer> dp = new ArrayList<>(); // LIS 배열을 유지하는 dp 리스트
for (int num : arr) {
int pos = Collections.binarySearch(dp, num); // num이 들어갈 위치를 이분 탐색으로 찾음
if (pos < 0) {
pos = -(pos + 1); // 삽입 위치를 음수값으로 반환하기 때문에 변환
}
if (pos == dp.size()) {
dp.add(num); // num이 가장 큰 값이면 추가
} else {
dp.set(pos, num); // num이 들어갈 위치에 대체
}
}
return dp.size(); // dp 리스트의 크기가 LIS의 길이
}
public static void main(String[] args) {
int[] arr = {10, 20, 10, 30, 20, 50};
System.out.println("이분 탐색 방식 LIS 길이: " + lisBinarySearch(arr)); // 출력: 4
}
}
관련 문제
- 실버 2 - 11053번 - 가장 긴 증가하는 부분 수열
- 골드 2 - 12015번 - 가장 긴 증가하는 부분 수열 2
- 골드 2 - 12738번 - 가장 긴 증가하는 부분 수열 3
- 실버 1 - 14002번 - 가장 긴 증가하는 부분 수열 4
- 골드 3 - 2352번 - 반도체 설계
728x90
'알고리즘 > 알고리즘 이론' 카테고리의 다른 글
[알고리즘 이론] 트라이(Trie) 알고리즘 개념 정리 및 문제 추천 (0) | 2025.01.07 |
---|---|
[알고리즘]크루스칼 알고리즘(kruskal's Algorithm) 정리 및 백준 문제 추천 (0) | 2024.09.04 |
[알고리즘] 플로이드-워셜 알고리즘 (0) | 2024.08.28 |
[알고리즘] 정렬(버블, 선택, 삽입) (2) | 2024.01.01 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- SSAFY
- 더오름
- SSAFYcial
- django
- 인프런강의
- 프로그래머스
- 오블완
- 웹개발
- 전자회로
- 생성형 AI
- dataframe
- 위니브엠베서더
- 백준
- 위니브
- 알고리즘이론
- 파이썬
- it도서큐레이션
- numpy
- Python
- 웹프로그래밍
- 백준알고리즘
- 인프런강의후기
- 제주코딩베이스캠프
- 알고리즘
- 코딩테스트
- PANDAS
- 웹
- 티스토리챌린지
- ssafy기자단
- 인프런
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함
250x250