일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 1916
- dijkstra
- 3745
- 논문리뷰
- 클린코드
- 자바
- 짝지어제거하기
- 알고리즘
- 머신러닝
- NLP
- 백준 1916 자바
- Alexnet
- 백준 1339 자바
- cs231n
- 관심사분리
- 1261
- 백준
- 백준9095
- 백준 1339
- 다익스트라
- 딥러닝
- 알렉스넷
- GPT
- 논문
- 1107번
- 논문구현
- deeplearning
- Java
- 디미터법칙
- MachineLearning
- Today
- Total
산 넘어 산 개발일지
[백준] 3745번 - 오름세(Java) 본문
풀이
키워드
- DP
- 이분 탐색
- LIS
LIS(최장 증가 부분 수열)
이분탐색에서 주로 나오는 LIS문제였다. DP랑 같이 합해져서 나오는 문제 중 자주 나오는 유형인 것 같다. 이런 LIS의 경우 방식은 다음과 같다.
1. List를 만들고 첫 번째 원소를 넣는다.
2. 다음 원소(Next)부터는 list의 맨 마지막 원소(Last)와 비교하며 조건마다 특정한 작업을 수행한다.
(조건 1) Last < Next
list의 마지막 뒤에 Next를 집어넣는다.(add())
(조건 2) Last >= Next
list 원소 중 Next와 같거나 Next보다 작으면서 가장 비슷한 원소의 바로 다음 원소를 삭제하고 그 자리에 Next를 넣는다. (가령, Last = 3 이고 List = [1, 2, 4]였다면 4자리에 3이 들어가는 것이다.)
이렇게 할 경우, (조건 1)에 의해 증가수열의 길이를 늘려가면서, (조건 2)에 의해 현재 증가수열보다 더 좋은 조건의 수열을 만날 경우, 그 수열로 수정해줄 수 있다. 이 때, 수정한다고 해도 [수정된 수열의 길이]가 [기존 수열의 길이]보다 길지 않다면, 결국 내가 현재 구하는 [최장증가수열의 길이]는 [수정된 수열의 길이]가 아닌 [기존 수열의 길이]가 된다는 것이 포인트이다.
이분탐색
이 때, Next가 들어갈 위치를 탐색하는 과정에서, 브루트포스로 일일이 탐색하면 시간이 너무 오래 걸린다. 여기서 이분탐색이 등장한다. List 안의 원소들을 이분탐색하여 Next가 들어갈 위치를 찾는 것이다.
이분탐색은 매번 쓸 때마다 헷갈리는데, 이번에 제대로 정리하자.
1. while 문 조건은 (start <= end)로 하자. 그래야 모든 원소를 탐색할 수 있다.
2. mid에 따른 조건은 3가지로 분기하자.
2-1. mid < Next
end = mid-1
2-2. mid == Next
break;
2-3. mid > Next
start = mid+1
3. 각 조건에 필요하다면 mid에 변화를 줄 수 있다.
예시로, 이번 문제의 경우 Next가 자신보다 작으면서 가장 비슷한 숫자 바로 다음에 와야 하므로, 2-3조건에 추가적으로 mid++를 주었다. 이후 while문이 break되더라도 mid는 [작으면서 가장 비슷한 숫자]가 아닌 그 다음 위치에 추가될 수 있도록 하기 위함이다.
입력
이번 문제의 경우, 입력에 여러 테스트케이스가 존재했는데, 총 테스트케이스가 주어지지 않았다. 이 경우 Scanner의 .hasNext()를 사용하면 되지만, Scanner 사용 시 속도가 너무 느려진다. 그래서 BufferedReader를 사용하는 방법을 알아보았다.
String input = null;
while ((input = br.readLine()) != null)
즉, 아무 입력이 없어도 .readLine()은 애러 없이 작동한다. 다만 null을 받아 올 뿐이다.
코드
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.StringTokenizer;
public class Main {
public static void main(String [] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
String input = null;
while((input = br.readLine()) != null) {
int N = Integer.parseInt(input.trim());
int [] arr = new int[N];
StringTokenizer st = new StringTokenizer(br.readLine());
for (int i = 0; i < N; i++) {
arr[i] = Integer.parseInt(st.nextToken());
}
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(arr[0]);
for (int i = 1; i < N; i++) {
int comp = list.get(list.size()-1);
if (comp < arr[i]) {
list.add(arr[i]);
}
else {
int start = 0;
int end = list.size()-1;
int mid = 0;
while(start <= end) {
mid = (start + end) / 2;
int cur = list.get(mid);
if (arr[i] < cur) {
end = mid - 1;
}
else if (arr[i] == cur) {
break;
}
else {
start = mid + 1;
mid++;
}
}
list.set(mid, arr[i]);
}
}
sb.append(list.size()).append("\n");
}
System.out.print(sb);
}
}
출처 : https://www.acmicpc.net/problem/3745
3745번: 오름세
입력은 여러개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스의 첫째 줄에는 주가를 관찰한 날의 수 N (N ≤ 100000)이 주어진다. 둘째 줄에는 관찰한 주가가 첫 날부터 순서대로 주어진다.
www.acmicpc.net
'알고리즘 > 백준' 카테고리의 다른 글
[백준] 1261번 - 알고스팟 (Java) (0) | 2021.05.20 |
---|---|
[백준] 1644번 - 소수의 연속합(Java) (0) | 2021.05.14 |
[백준] 1107번 - 리모컨(Java) (0) | 2021.04.14 |
[백준] 1916번 - 최소비용 구하기 (Java) (0) | 2021.04.07 |
[백준] 1339번 - 단어 수학 (Java) (0) | 2021.04.06 |