ALGOSPOT
LIS Longest Increasing Sequence / ALGOSPOT
건이두
2020. 2. 5. 19:10
728x90
문제링크 : https://algospot.com/judge/problem/read/LIS
제출링크 : https://algospot.com/judge/submission/detail/655189
자바소스 : https://github.com/skysign/WSAPT/blob/master/ALGOSPOT/LIS/src/Main.java
이 문제는 1차원 DP 문제로, O(N^2)로 풀수 있는 문제입니다.
아래의 LIS()메서드를 참고하세요.
문제 푸는 것 보다, 책의 코드 8.12 li3()함수를 이해하는 것이 더 어려웠던 문제입니다.
보시는 분들의 이해를 돕기 위해서, lis3() 함수를 자바 버전으로 구현해 봤습니다.
(코드 8.12에서 사용된 변수명과 아래 메서드에서 사용된 변수명이 같다면, 역할이 동일합니다.)
public int lis3(int start) {
if(cache[start+1] != 0)
return cache[start+1];
int r = 1;
cache[start+1] = r;
for(int next=start+1; next<n; ++next) {
if((start == -1) || (S[start] < S[next])) {
r = Math.max(r, lis3(next)+1);
cache[start+1] = r;
}
}
return r;
}
아래의 루프 1개를 가지고, 2가지 목적으로 사용하는 것이 lis2()와 lis3()의 주된 차이점입니다.
for(int next=start+1; next<n; ++next)
- 0 부터 N까지 한번씩 lis3()를 호출 한다.
- S[start] < S[next] 가 true면 lis3(next+1)을 호출 한다.
위의 메서드가 start는 -1인 상태로 호출되는 것이 포인트 입니다.
따라서, 첫번째 루프가 start가 -1인 상태로 위의 #1을 실행하는 목적이구요,
두번째 루프, 즉 start가 0 부터 호출되는 루프는 위의 #2를 실행하는 목적입니다.
이렇게 루프가 실행되면서, 중복해서 lis3()가 호출 될 것 같지만,
cache를 사용해서, 한번 방문한 곳은 중복해서 방문하지 않기 때문에, 중복된 lis3() 호출은 발생하지 않습니다.
import java.util.Scanner;
/**
* LIS Longest Increasing Sequence / ALGOSPOT
* 문제링크 : https://algospot.com/judge/problem/read/LIS
* 제출링크 : https://algospot.com/judge/submission/detail/655189
*/
public class Main {
Scanner sc = new Scanner(System.in);
int[] cache;
int n = 0;
int[] S;
public void solve() {
int T = sc.nextInt();
int r = 0;
for(int t=0; t<T; ++t) {
int N = sc.nextInt();
n = N;
S = new int[N];
for(int i=0; i<N; ++i) {
S[i] = sc.nextInt();
}
// r = LIS(S, N);
// System.out.println(r);
cache = new int[N+1];
r = lis3(-1);
System.out.println(r-1);
}
}
public int LIS(int[] map, int N) {
int[] dp = new int[N+1];
for(int i=0; i<N; ++i) {
int max = 1;
for(int k=0; k<i; ++k) {
if(map[k] < map[i])
max = Math.max(max, dp[k]+1);
}
dp[i] = max;
}
int r = 0;
for(int i=0; i<N; ++i) {
r = Math.max(r, dp[i]);
}
return r;
}
/**
* 책 234페이지, 코드 8.12를 자바버전으로 구현한 메서드 입니다.
* 코드 보시는 분들이 헷갈리지 않도록, ret를 제외하고는, 코드 8.12에서 사용된
* 변수명과 아래 메서드에서 사용된 변수명이 같다면, 역할도 동일합니다.
* @param start
* @return
*/
public int lis3(int start) {
if(cache[start+1] != 0)
return cache[start+1];
int r = 1;
cache[start+1] = r;
for(int next=start+1; next<n; ++next) {
if((start == -1) || (S[start] < S[next])) {
r = Math.max(r, lis3(next)+1);
cache[start+1] = r;
}
}
return r;
}
public static void main(String[] args) {
Main main = new Main();
main.solve();
}
}
728x90