# 11054번 : 가장 긴 바이토닉 부분
n = int(input())
li = list(map(int,input().split()))
#증가하는 수열 - LIS
dp_inc = [1 for i in range(n)]
for i in range(n):
for j in range(i):
if li[i] > li[j]:
dp_inc[i] = max(dp_inc[i],dp_inc[j]+1)
li.reverse()
#감소하는 수열 - DIS
dp_desc = [1 for i in range(n)]
for i in range(n):
for j in range(i):
if li[i] > li[j]:
dp_desc[i] = max(dp_desc[i],dp_desc[j]+1)
dp_desc.reverse()
ans = [0 for i in range(n)]
for i in range(n):
ans[i] = dp_inc[i]+dp_desc[i]
print(max(ans)-1)
바이토닉 부분수열은 가장 긴 증가하는 부분수열(LIS)와 가장 긴 감소하는 부분수열을 합쳐서 생각하면 금방 풀리는 문제이다. 그러나 나는 LIS문제를 이전에 접해본 적이 없기 때문에 LIS알고리즘을 이해하는 것부터 시작했다.
LIS(longest Inscreasing Subsequence) - 가장 긴 증가하는 부분수열
어떤 임의의 수열이 주어질 때, 이 수열에서 몇 개의 수들을 제거해서 부분수열을 만들 수 있다.
이때 만들어진 부분수열 중 오름차순으로 정렬된 가장 긴 수열을 최장 증가 부분 수열이라 한다.
예를 들어 {10,20,10,30,20,50} 이런 수열이 있을 때 {10,20,10,30,20,50} 이렇게 굵게 표시한 숫자들이 LIS가 되며 이 부분수열의 길이는 4가 된다.
그렇다면 LIS의 길이를 구하는 알고리즘은 어떻게 만들 수 있을까?
총 2가지의 방법이 있다.
1. 동적프로그래밍(DP)을 사용하는 시간복잡도 O(N^2) 의 알고리즘
위의 코드는 이 알고리즘을 구현한 것이다.
- 먼저 수열의 개수만큼의 dp리스트를 1로 초기화한다.
- 현재 위치의(i) 원소의 값이 이전에 있는 원소들(j)의 값보다 큰 값인지 확인한다.(같은 경우는 증가하는 부분수열이 될 수 없으므로 안된다.)
- 만약 현재 위치의 원소(i)가 이전에 있는 원소(j)보다 값이 크다면 dp[j] 중 가장 큰 값에 +1을 한 값을 dp[i]로 한다.
시간복잡도는 i개의 수열에 대해서 2번 반복문을 돌며 비교하니깐 O(N^2)가 된다.
2. 이분탐색(binary search)를 활용한 시간복잡도 O(N log N)의 알고리즘
이 알고리즘은 두번째 반복문을 돌지 않고 이분탐색 알고리즘을 사용하기 때문에 시간복잡도가 DP를 이용할 때 보다 더 작다.
아래 코드는 binary search를 이용해서 가장 긴 증가하는 부분수열의 길이를 구하는 알고리즘이다.
# binary search를 이용한 증가하는 부분수열
n = int(input())
array = list(map(int, input().split()))
stack = [0]
def binary_search(target, start, end):
while start <= end:
mid = (start + end) // 2
if stack[mid] < target:
start = mid + 1
else:
end = mid - 1
return start
for i in array:
if stack[-1] < i:
stack.append(i)
else:
stack[binary_search(i, 0, len(stack) - 1)] = i
print(len(stack) - 1)
참고 사이트
728x90
'알고리즘 문제풀이 > Dynamic programming' 카테고리의 다른 글
(파이썬 python) 백준 11051번 : 이항 계수 2 (0) | 2022.11.06 |
---|---|
(파이썬 python) 백준 11055번 : 가장 긴 증가 부분 수열 (0) | 2022.11.03 |
(파이썬 python) 백준 11057번 : 오르막 수 (0) | 2022.10.28 |
(파이썬 python) 백준 2293번 : 동전 1 (0) | 2022.10.28 |
(파이썬 python) 백준 9465번 : 스티커 (0) | 2022.10.26 |