Problem : 가장 긴 증가하는 부분 수열 5
유형 : LIS, Backtracking
문제 설명
수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오.
예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에
가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이고, 길이는 4이다.
예제 입력
첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다.
둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (-1,000,000,000 ≤ Ai ≤ 1,000,000,000)
1 |
|
예제 출력
출력 설명
1 |
|
해결 전략
이분탐색을 이용하여 LIS 길이를 찾는다.
부분 수열을 백트래킹 해서 찾는다.
LIS를 만들때, path에 {숫자, 숫자가 등장한 idx} 를 보관해서 풀어야 한다.
LIS 길이를 구한 후, path에 담긴 원소들을 뒤에서부터 차례대로 탐색해야 정상적인 경로를 뽑을 수 있다.
주의할 점
- 삽입시 자신의 앞 경로를 LIS를 만들기 위한 벡터내의 앞 숫자로 잡으면 틀린다.
- 맞왜틀 하고 있다면 아래의 반례를 넣어보기 바란다.
1 |
|
풀이
LIS를 이분탐색을 이용하여 구한다.
- LIS를 만들기 위해 초기 원소는 나올 수 없는 최소의 수로 한다.
INT_MIN
- 맨 뒤보다 들어가려는 숫자
num
이 더 크다면, 뒤에 넣는다. - 그렇지 않다면, 최적의 위치를
lower_bound
를 이용해 찾아서 넣는다. - 두가지 경우 모두 LIS를 위한 벡터에 삽입할 때마다
path
에 해당num
이 LIS를 구성할때 어느 위치에 있는지를 찾아 같이 넣어준다.
경로를 찾는다.
path
의 맨 뒤에서부터 탐색한다.- 만약
path
안의 원소의 위치 index가, LIS를 이루는 수열 index와 같다면- 해당 숫자는 LIS를 이루는 구성 요소가 된다.
- 스택에 넣는다.
- 해당 숫자는 LIS를 이루는 구성 요소가 된다.
- 스택안에 들어간것을 역순으로 출력한다.
코드
1 |
|
피드백
뭔가 글로 설명하려니 굉장히 힘드네요
나의 경우에도 주의할점 을 놓치고 있어서 맞왜틀 하고 있었다.