From e1c89310285d1606365114f1b882e9c2d470e32c Mon Sep 17 00:00:00 2001 From: Rekalux Date: Thu, 30 Sep 2021 22:32:55 +0900 Subject: [PATCH 1/4] =?UTF-8?q?code:=20Vinjunho=20boj=207662=20=EC=9D=B4?= =?UTF-8?q?=EC=A4=91=EC=9A=B0=EC=84=A0=EC=88=9C=EC=9C=84=ED=81=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Vinjunho/boj/7662/boj7662.java | 49 ++++++++++++++++++++++++++++++++++ Vinjunho/boj/7662/boj7662.py | 25 +++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 Vinjunho/boj/7662/boj7662.java create mode 100644 Vinjunho/boj/7662/boj7662.py diff --git a/Vinjunho/boj/7662/boj7662.java b/Vinjunho/boj/7662/boj7662.java new file mode 100644 index 0000000..1292f36 --- /dev/null +++ b/Vinjunho/boj/7662/boj7662.java @@ -0,0 +1,49 @@ +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.StringTokenizer; +import java.util.TreeMap; + +public class boj7662 { + public static void main(String[] args) throws IOException { + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + int T = Integer.parseInt(br.readLine()); + for (int tc = 0; tc < T; tc++) { + int n = Integer.parseInt(br.readLine()); + TreeMap map = new TreeMap(); + // TreeMap은 정렬과 동시에 Map의 역할을 수행 key는 입력받은 숫자, value는 개수 + for (int i = 0; i < n; i++) { + StringTokenizer st = new StringTokenizer(br.readLine()); + String command = st.nextToken(); + int num = Integer.parseInt(st.nextToken()); + if (command.equals("I")) { + if (map.containsKey(num)) { // 이미 존재하는 값이면 + map.put(num, map.get(num) + 1); // 개수만 증가 + } else { + map.put(num, 1); // 없으면 추가 + } + } else { + if (map.size() > 0) { + int del_key = 0; // 지울 key 초기화 + if (num == 1) { + del_key = map.lastKey(); // 가장 뒤에 있는 = 가장 키값이 큰 + } else { + del_key = map.firstKey(); // 가장 앞에 있는 = 가장 키값이 작은 + } + int del_num = map.get(del_key) - 1; // 개수를 줄여보고 + if (del_num == 0) { // 0이면 삭제 + map.remove(del_key); + } else { + map.put(del_key, del_num); // 그 외엔 업데이트 + } + } + } + } + if (map.size() == 0) { + System.out.println("EMPTY"); + } else { + System.out.println(map.lastKey() + " " + map.firstKey()); + } + } + } +} \ No newline at end of file diff --git a/Vinjunho/boj/7662/boj7662.py b/Vinjunho/boj/7662/boj7662.py new file mode 100644 index 0000000..6f2b535 --- /dev/null +++ b/Vinjunho/boj/7662/boj7662.py @@ -0,0 +1,25 @@ +import sys +import heapq + +input = sys.stdin.readline +T = int(input()) +for _ in range(T): + n = int(input()) + nq, mq = [], [] + visit = [False] * (n + 1) # 지워진 번호 (입력된 순서) + for i in range(n): + command, num = input().split() + num = int(num) + if command == 'I': # 입력 명령이면 + heapq.heappush(nq, (num, i)) # 작은수우선 + heapq.heappush(mq, (-num, i)) # 큰수우선 + continue + elif num == 1 and mq: # 지우라는 명령어에 지울 값이 있으면 + visit[heapq.heappop(mq)[1]] = True # 입력된 값을 지우고 지웠음을 저장한다 + elif num == -1 and nq: # 지우라는 명령어에 지울 값이 없으면 + visit[heapq.heappop(nq)[1]] = True # 입력된 값을 지우고 지웠음을 저장한다 + while nq and visit[nq[0][1]]: # nq에서 제거할 수 있을만큼 제거하겠다. + heapq.heappop(nq) + while mq and visit[mq[0][1]]: # mq에서 제거할 수 있을만큼 제거하겠다. + heapq.heappop(mq) + print(f'{-mq[0][0]} {nq[0][0]}' if nq else 'EMPTY') From d552eaec37d4d36c89b39e3e71858b7268185b3e Mon Sep 17 00:00:00 2001 From: Rekalux Date: Thu, 30 Sep 2021 22:33:21 +0900 Subject: [PATCH 2/4] =?UTF-8?q?docs:=20Vinjunho=20boj=207662=20=EC=9D=B4?= =?UTF-8?q?=EC=A4=91=EC=9A=B0=EC=84=A0=EC=88=9C=EC=9C=84=ED=81=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Vinjunho/boj/7662/README.md | 144 ++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 Vinjunho/boj/7662/README.md diff --git a/Vinjunho/boj/7662/README.md b/Vinjunho/boj/7662/README.md new file mode 100644 index 0000000..61769d6 --- /dev/null +++ b/Vinjunho/boj/7662/README.md @@ -0,0 +1,144 @@ +# 백준 7662 이중 우선순위 큐 + +[문제 링크](https://www.acmicpc.net/problem/7662) + +## 1. 설계 로직 + +- ### java + +1. 입력과 출력에 log(n) 을 원함 +2. 정렬된 자료구조가 필요함 +3. 중복을 제거해 줄 자료구조가 필요함 +4. Treemap으로 한 번에 해결 +5. I면 Treemap에 넣고 이미 존재하면 개수만 늘린다 +6. D 1 이면 lastkey를 활용해 맨 오른쪽 노드 제거, D -1이면 firstkey를 활용해 맨 왼쪽 노드 제거(개수가 남아 있다면 개수만 1 줄임) +7. 비어있다면 Entry, 존재하면 lastkey, firstkey를 각각 출력한다 + +- n log(n) + + + +- ### python + +1. 입력과 출력에 log(n) 을 원함 +2. 정렬된 자료구조가 필요함 +3. 중복을 제거해 줄 자료구조가 필요함 +4. 작은 수를 기준으로 하는 우선순위 큐, 큰 수를 기준으로 하는 우선순위 큐 이렇게 2개 만든다 +5. I이면 두 큐에 모두 저장한다. 단, 인덱스 값을 넣어서 서로가 같은 수임을 인식시킨다 +6. D 1 이면 내림차순 큐에서 제거, D -1이면 오름차순 큐에서 제거 +7. 하나의 명령이 끝날 때마다 동시에 pop 값이 없는지 양쪽 큐를 확인한다. 있다면 최대한 pop한다. +8. 비어있다면 Entry, 존재하면 각 큐를 pop하여 출력한다 + +- n log(n) + +## 2. 코드 + +- ### java + +```python +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.StringTokenizer; +import java.util.TreeMap; + +public class Main { + public static void main(String[] args) throws IOException { + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + int T = Integer.parseInt(br.readLine()); + for (int tc = 0; tc < T; tc++) { + int n = Integer.parseInt(br.readLine()); + TreeMap map = new TreeMap(); + for (int i = 0; i < n; i++) { + StringTokenizer st = new StringTokenizer(br.readLine()); + String command = st.nextToken(); + int num = Integer.parseInt(st.nextToken()); + if (command.equals("I")) { + if (map.containsKey(num)) { + map.put(num, map.get(num) + 1); + } else { + map.put(num, 1); + } + } else { + if (map.size() > 0) { + int del_key = 0; + if (num == 1) { + del_key = map.lastKey(); + } else { + del_key = map.firstKey(); + } + int del_num = map.get(del_key) - 1; + if (del_num == 0) { + map.remove(del_key); + } else { + map.put(del_key, del_num); + } + } + } + } + if (map.size() == 0) { + System.out.println("EMPTY"); + } else { + System.out.println(map.lastKey() + " " + map.firstKey()); + } + } + + } +} +``` + +- ### python + +``` +import sys +import heapq + +input = sys.stdin.readline +T = int(input()) +for _ in range(T): + n = int(input()) + nq, mq = [], [] + visit = [False] * (n + 1) # 지워진 번호 (입력된 순서) + for i in range(n): + command, num = input().split() + num = int(num) + if command == 'I': # 입력 명령이면 + heapq.heappush(nq, (num, i)) # 작은수우선 + heapq.heappush(mq, (-num, i)) # 큰수우선 + continue + elif num == 1 and mq: # 지우라는 명령어에 지울 값이 있으면 + visit[heapq.heappop(mq)[1]] = True # 입력된 값을 지우고 지웠음을 저장한다 + elif num == -1 and nq: # 지우라는 명령어에 지울 값이 없으면 + visit[heapq.heappop(nq)[1]] = True # 입력된 값을 지우고 지웠음을 저장한다 + while nq and visit[nq[0][1]]: # nq에서 제거할 수 있을만큼 제거하겠다. + heapq.heappop(nq) + while mq and visit[mq[0][1]]: # mq에서 제거할 수 있을만큼 제거하겠다. + heapq.heappop(mq) + print(f'{-mq[0][0]} {nq[0][0]}' if nq else 'EMPTY') + +``` + +## 3. 후기 + +- ### java + +- 이 문제는 AVL Tree 혹은 Red-Black Tree를 활용하라는 문제로 보인다. + +- 그러나 이 문제에서 자료구조 그 자체를 구현하기에는 무리가 있으므로 있는 자료구조를 활용해서 최대한 문제에 접근하는 것이 중요하겠다. + +- Java에는 Treemap이라는 파워풀한 자료구조(RB Tree 기반)가 존재해서 쉽게 풀 수 있었다. + +- Treemap은 Map의 Key, Value값을 가지면서 이분탐색트리의 구조를 띄고 있어 정렬된 구조를 갖는다. + +- 입력,출력에 log(n) 밖에 걸리지않고, 내부적으로 균형을 맞추기위해 회전도 알아서 해준다. + +- 자바 사기 + +- ### python + +- Python에는 정렬이 되며 이분탐색하는 자료구조는 존재하지 않는다. 있다고 하더라도 삭제에 log(n) 이 소모되는 자료구조는 기본적으로 제공하지 않는듯하다. +- 우리가 알아야 할 값은 최소값, 최대값으로 기준이 2개이므로 각각의 기준에 맞는 우선순위큐를 활용한다. +- 서로의 큐가 같은 데이터를 공유하고 있어야 한다는 점에서 인덱스를 활용하는 방법과 dictionary를 활용하는 2가지의 방법이 있겠다 +- 삽입에 이분탐색을 적용하고 삭제에 O(n)을 소비시켜도 통과하는 것도 확인했다. 저격케이스 뜨면 바로 시간초과다. 그러나 의도가 중복을 제거하라는 부분이라 삭제 시간 초과는 큰 문제가 아닌 것 같다. 심지어는 속도도 더 빠른 결과가 나와 오히려 당황스럽다. 하하 +- 자바 사기 + From 9702cdbd3c1e249642e547f5fea270f3eb275b5a Mon Sep 17 00:00:00 2001 From: Rekalux Date: Tue, 5 Oct 2021 22:14:04 +0900 Subject: [PATCH 3/4] =?UTF-8?q?code:=20Vinjunho=20boj=202075=20N=EB=B2=88?= =?UTF-8?q?=EC=A7=B8=ED=81=B0=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Vinjunho/boj/2075/boj2075.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 Vinjunho/boj/2075/boj2075.py diff --git a/Vinjunho/boj/2075/boj2075.py b/Vinjunho/boj/2075/boj2075.py new file mode 100644 index 0000000..2194911 --- /dev/null +++ b/Vinjunho/boj/2075/boj2075.py @@ -0,0 +1,12 @@ +import sys, bisect + +input = sys.stdin.readline +n = int(input()) +lank = [] # 상위 n개의 수만 관리할 list +for _ in range(n): + li = list(map(int, input().split())) # readline + for i in range(n): + bisect.insort(lank, -li[i]) # 크기순으로 정렬하며 삽입한다(bisect는 이분탐색활용하므로 O(log(n)) + if len(lank) > n: # 상위 n번째 이 후의 수는 볼 이유 없으므로 삭제 + lank.pop() # 리스트 맨 끝을 날리는 pop()함수는 O(1) +print(-lank[-1]) # n번째 수를 출력 From 324147f8eb5963e0b0e42aa831432beb8b65d62d Mon Sep 17 00:00:00 2001 From: Rekalux Date: Tue, 5 Oct 2021 22:16:06 +0900 Subject: [PATCH 4/4] =?UTF-8?q?docs:=20Vinjunho=20boj=202075=20N=EB=B2=88?= =?UTF-8?q?=EC=A7=B8=ED=81=B0=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Vinjunho/boj/2075/README.md | 41 +++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Vinjunho/boj/2075/README.md diff --git a/Vinjunho/boj/2075/README.md b/Vinjunho/boj/2075/README.md new file mode 100644 index 0000000..f34267c --- /dev/null +++ b/Vinjunho/boj/2075/README.md @@ -0,0 +1,41 @@ +# 백준 2075 N번째 큰 수 + +[문제 링크](https://www.acmicpc.net/problem/7662) + +## 1. 설계 로직 + +1. n^2개의 수 중에서 n번째의 수를 구하는 문제이다. +2. n^2개의 데이터를 모두 관리할 필요가 없다 +3. 상위 n개만 관리하여 n번째 수를 뽑아내면 되겠다. +4. 이분탐색을 통해 랭킹을 관리하면 더 효율적. + + + +- (n^2)log(n) , 1<=n<=1500 + +## 2. 코드 + +```python +import sys, bisect + +input = sys.stdin.readline +n = int(input()) +lank = [] # 상위 n개의 수만 관리할 list +for _ in range(n): + li = list(map(int, input().split())) # readline + for i in range(n): + bisect.insort(lank, -li[i]) # 크기순으로 정렬하며 삽입한다(bisect는 이분탐색활용하므로 O(log(n)) + if len(lank) > n: # 상위 n번째 이 후의 수는 볼 이유 없으므로 삭제 + lank.pop() # 리스트 맨 끝을 날리는 pop()함수는 O(1) +print(-lank[-1]) # n번째 수를 출력 + +``` + + + +## 3. 후기 + +- 어제 우선순위큐와 이분탐색에 대해 공부하다 bisect라는 말도 안 되는 라이브러리를 알게되었다. +- 앞으로 이분탐색이 필요할 때 많이 써먹어야겠다. +- 파이썬 사기 +