-
Notifications
You must be signed in to change notification settings - Fork 5
11-janghw0126 #160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
11-janghw0126 #160
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고민하다가 결국 모르겠어서 솔루션을 찾아봤습니다...! Java에 TreeMap이라는 게 있는데, 이걸 이용하면 lastKey(), firstKey() 메서드로 이중 우선순위 큐를 구현할 수 있었습니다
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.StringTokenizer;
import java.util.TreeMap;
public class Num7662 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder printSet = new StringBuilder();
int T = Integer.parseInt(br.readLine());
for(int test = 0; test < T; test++) {
int K = Integer.parseInt(br.readLine());
TreeMap<Integer, Integer> map = new TreeMap<>();
for(int i = 0; i < K; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
String oper = st.nextToken();
int num = Integer.parseInt(st.nextToken());
if(oper.equals("I")) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
else if(oper.equals("D")) {
if(map.size() == 0) continue;
int removeNum;
if(num == 1) { //최댓값 삭제
removeNum = map.lastKey();
}
else { // 최솟값 삭제
removeNum = map.firstKey();
}
if(map.put(removeNum, map.get(removeNum) - 1) == 1) {
map.remove(removeNum);
}
}
}
if (map.size()==0) {
printSet.append("EMPTY\n");
} else {
printSet.append(map.lastKey() + " " + map.firstKey() + "\n");
}
}
System.out.print(printSet);
}
}
@jung0115 Java에 TreeMap이라는 것이 있군요! 요즘 자바를 공부 중에 있는데 덕분에 새로운 컬렉션을 알아갑니다🧐👍 |
코드를 조금 더 최적화해본 결과를 공유드립니다 ! 모든 원소에 대해 상태를 저장하지 않고 삭제된 인덱스만 저장되도록 매 연산마다 status 배열을 확인하고 업데이트하지 않고 삭제된 원소만 확인할 수 있도록 개선합니다 ! import sys
import heapq
input = sys.stdin.readline
T = int(input())
for _ in range(T):
k = int(input())
min_heap = []
max_heap = []
removed = set() # 삭제된 원소의 인덱스를 추적하는 집합 - O(1) 탐색 가능
for i in range(k):
cmd, num = input().split()
num = int(num)
if cmd == 'I':
# (값, 인덱스) 튜플로 저장하여 각 원소를 고유하게 식별
# 동일한 값이 들어와도 인덱스가 다르므로 구별 가능
heapq.heappush(min_heap, (num, i)) # O(log n)
heapq.heappush(max_heap, (-num, i)) # O(log n)
else:
if num == 1: # 최댓값 제거
# 이미 제거된 원소들을 실제로 제거
while max_heap and max_heap[0][1] in removed: # O(1) 탐색
heapq.heappop(max_heap) # O(log n)
if max_heap:
removed.add(max_heap[0][1]) # O(1)
heapq.heappop(max_heap) # O(log n)
else: # 최솟값 제거
while min_heap and min_heap[0][1] in removed:
heapq.heappop(min_heap)
if min_heap:
removed.add(min_heap[0][1])
heapq.heappop(min_heap)
# 최종 출력 전 남은 제거된 원소들 정리
while max_heap and max_heap[0][1] in removed:
heapq.heappop(max_heap)
while min_heap and min_heap[0][1] in removed:
heapq.heappop(min_heap)
# 둘 중 하나라도 비어있으면 EMPTY 출력
if not max_heap or not min_heap:
print("EMPTY")
else:
# 최댓값은 음수로 저장했으므로 다시 양수로 변환
print(-max_heap[0][0], min_heap[0][0]) 이중 우선순위 큐를 구현하는 방법에 대해 배워갈 수 있었습니다 ! 'U' |
🔗 문제 링크
백준 | 이중 우선순위 큐
✔️ 소요된 시간
3시간 + @..
✨ 수도 코드
오늘 풀 문제를 찾아보다가 이중 우선순위 큐 문제가 딱 눈에 띄어서 풀어보았습니다. 우선순위 큐 개념은 확실히 잡혀있는데 이와 관련된 문제를 풀어보면 뭔가 응용능력이 2프로 부족한 느낌이라 관련 문제들을 계속 풀어보면서 마스터하기 위해 이번 문제를 한번 도전해보았습니다!
🔥 1차 시도
문제를 보면, 이중 우선순위 큐를 구현하라고 적혀있습니다.
일반적인 우선순위 큐와는 다른 점은 데이터를 삭제할 때 우선순위가 높은 데이터와 낮은 데이터 두 개를 모두 고려해야 한다는 점입니다. 따라서, 코드를 구현할 때 최대힙과 최소힙을 모두 생각해서 풀어나가야 됩니다. 그래서 저는 최대힙을 저장하는 리스트와 최소힙을 저장하는 리스트를 따로 정하고 문제의 지문대로 코드를 구현해 나갔습니다.
Note
핵심 로직
최대힙을 저장하는 리스트와 최소힙을 저장하는 리스트를 선언합니다.
1.
명령어가 I일 때,
2.
명령어가 D일 때,
pop
해줍니다.👩💻 1차 시도 코드
이렇게 풀었더니 테스트 케이스는 통과했는데

시간초과가 났습니다..
시간초과가 난 원인을 찾아보니,
pop
메소드를 사용할 경우 리스트의 마지막 요소를 제거하는 것이기 때문에, 힙의 구조를 유지할 수 없다고 합니다.생각해보니까, 힙은 트리구조이므로 최댓값이나 최솟값 삭제를
pop
으로 사용하면 안되겠다는 생각을 하였습니다.💦 2차 시도
그래서 어떻게 해결해야 될지 한참 고민해보다가 아래의 로직인
Note
원소가 삭제되었는지 여부를 기록하면서, 힙에서 유효하지 않은 값을 제거해준다
를 사용해주면 힙의 구조를 유지하면서 최댓값과 최솟값을 삭제할 수 있겠다는 생각을 하였습니다.
여부를 기록하는 이유는 만약 어느 한 힙에서 그 값이 삭제되었다면, 그 값은 더 이상 유효하지 않다고 볼 수 있습니다. 하지만 삭제되었다고 바로 다른 힙에서도 자동으로 사라지지는 않기 때문에, 다른 힙에 그 값이 남아 있을 수 있으므로 이를 유효하지 않은 값으로 처리합니다.
따라서, 유효한 값만을 남기기 위해서 유효하지 않은 값을 삭제해줍니다.
👩💻 최종 코드
📚 새롭게 알게된 내용
우선순위 큐의 특성을 제대로 파악하지 못하고
pop
을 쓰다니,, 저는 바부입니다🥔😭무난할 줄 알았던 문제였는데 결국 하루종일 붙잡고 있었습니다,, ㅠㅠ
통과가 되었긴 했는데, 제 코드가 가독성이 꽝인 것 같아서...
더 좋은 아이디어가 있을 것 같은데 알려주세요!!