본문 바로가기

Java/백준

[JAVA] 백준 12015 가장 긴 증가하는 부분 수열 2

https://www.acmicpc.net/problem/12015

 

12015번: 가장 긴 증가하는 부분 수열 2

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ Ai ≤ 1,000,000)

www.acmicpc.net

 

- 수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램

- 예를 들어, 수열 A={10,20,10,30,20,50}인 경우에 가장 긴 증가하는 부분 수열은  A={10,20,10,30,20,50}이고 길이는 4이다.

 

 

문제 풀이 

 

가장 긴 증가하는 부분 수열 LIS

[백준] 12015번 : 가장 긴 증가하는 부분 수열 2 - JAVA [자바] (tistory.com)

 

[백준] 12015번 : 가장 긴 증가하는 부분 수열 2 - JAVA [자바]

https://www.acmicpc.net/problem/12015 12015번: 가장 긴 증가하는 부분 수열 2 첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ Ai ≤ 1,000,000) w

st-lab.tistory.com

[C++] 백준 12015 - 가장 긴 증가하는 부분 수열 2 (dp, 이분 탐색, 메모이제이션) :: 코린이의 작업공간 (tistory.com)

 

[C++] 백준 12015 - 가장 긴 증가하는 부분 수열 2 (dp, 이분 탐색, 메모이제이션)

0. [c++] 백준 https://www.acmicpc.net/problem/12015 1. 풀이 1) 동적계획법을 활용한 풀이우선 이 풀이는 O(N^2)의 풀이이다.풀이 방법은 다음과 같다.1. cache라는 배열은 cache[i] = i번째 수를 기준으로 만들 수

kyunstudio.tistory.com

- LIS(Longest Increasing Subsequence)는 불연속 상관없이 가장 긴 증가하는 부분 수열을 구하는 알고리즘 

- DP을 활용시 단순하지만 시간 복잡도가 O(n^2)을 가짐

- 이진 탐색을 활용하면 시간복잡도를 O(nlogn)을 가짐

 

이진 탐색으로 풀이 

 

- DP 방식과 동일하게 메모제이션을 활용하지만, 저장하는 데이터를 다르게 구현 

- 포인트는 각 배열의 마지막 수를 저장해주는 것

 

ex)

10,20,30,25,15,60이라는 배열이 있을 때, LIS를 탐색하는 과정 

 

1) memo[0]에 10이 저장됨

2) memo[0](=10) < 20 이므로, memo[1]에 20이 저장됨

3) memo[1](=20) < 30 이므로, memo[2]에 30이 저장됨

4) memo[2](=30)>25 이므로, 부분 수열의 길이를 증가시키는 것은 불가능하고, memo[2]에 저장되어 있던 30을 25로 치환해줌

5) memo[3](=25)>15 이므로, 부분 수열의 길이를 증가시키는 것은 불가능하고, memo[1]에 저장되어 있는 20을 15로 치환 

 

- 최종적으로 memo는 10,15,25,60을 저장하게 됨 

- 이때 memo의 크기가 LIS의 크기와 동일하게 됨 

 

 

정답 

 

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;

public class Main 
{
    static int memo[];
    public static void main(String[] args) throws IOException
    {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        
        int N = Integer.parseInt(br.readLine());
        
        int A[] =new int[N];
        
        StringTokenizer st = new StringTokenizer(br.readLine());
        for(int i=0; i<N; i++)
        {
            A[i] = Integer.parseInt(st.nextToken());
        }
        
        memo = new int[N];
        
        //memo 초기 값으로 첫 번째 수열의 값을 가짐
        memo[0] = A[0];
        int len = 1; //LIS의 길이 
        
        for(int i=1; i<N; i++)
        {
            int key = A[i];
            
            //만약 key가 memo의 마지막 값보다 클 경우 추가
            if(memo[len-1]<key)
            {
                len++;
                memo[len-1] = key;
            }
            else
            {
                //이분 탐색
                int low = 0;
                int high = len;
                while(low<high)
                {
                    int mid = (low+high)/2;
                    
                    if(memo[mid]<key)
                    {
                        low = mid+1;
                    }
                    else
                    {
                        high = mid;
                    }
                }
                //low가 memo에서 대치 될 원소의 위치가 될 것이고 
                //해당 위치에 key값으로 원소를 바꿔준다.
                memo[low] = key;
                
            }
        }
        
        bw.write(String.valueOf(len));
        
        bw.flush();
        bw.close();
            
    }
}

 

 

'Java > 백준' 카테고리의 다른 글

[JAVA] 백준 11049 행렬 곱셈 순서  (0) 2024.03.24
[JAVA] 백준 11066 파일 합치기  (1) 2024.03.22
[JAVA] 백준 1450 냅색문제  (0) 2024.03.20
[JAVA] 백준 1644 소수의 연속합  (7) 2024.03.19
[JAVA] 백준 1806 부분합  (0) 2024.03.18