https://school.programmers.co.kr/learn/courses/30/lessons/42628#
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
풀이 1
처음에 푼 풀이는 다음과 같다.
- 최댓값과 최솟값을 구해야 하므로 큰 수를 우선으로 하는 우선순위 큐, 작은 수를 우선으로 하는 우선순위 큐 총 2개를 사용하면 된다.
- 그런데 하나의 큐에서 제거된 값이 여전히 다른 큐에는 남아있으므로, 두 큐에 공통되게 담긴 수를 의미하는 set을 두었다.
- 그러고 하나의 큐에서 값을 제거할 때 정말 실제로 큐에 남아있는 값인지(두 큐에 공통되게 있는지) set.contains()를 통해 먼저 확인하는 과정을 거쳤다.
import java.util.*;
class Solution {
public int[] solution(String[] operations) {
Set<Integer> set = new HashSet<>();
PriorityQueue<Integer> minQue = new PriorityQueue<>();
PriorityQueue<Integer> maxQue = new PriorityQueue<>((o1, o2) -> o2 - o1);
for (String s : operations) {
String op = s.split(" ")[0];
int num = Integer.parseInt(s.split(" ")[1]);
if (op.equals("I")) {
set.add(num);
minQue.add(num);
maxQue.add(num);
}
if (op.equals("D") && num == 1) {
while (!maxQue.isEmpty()) {
int poll = maxQue.poll();
if (set.contains(poll)) {
set.remove(poll);
break;
}
}
}
if (op.equals("D") && num == -1) {
while (!minQue.isEmpty()) {
int poll = minQue.poll();
if (set.contains(poll)) {
set.remove(poll);
break;
}
}
}
}
int[] answer = new int[2];
if (set.size() == 0) {
return answer;
}
while (!maxQue.isEmpty()) {
int poll = maxQue.poll();
if (set.contains(poll)) {
answer[0] = poll;
break;
}
}
while (!minQue.isEmpty()) {
int poll = minQue.poll();
if (set.contains(poll)) {
answer[1] = poll;
break;
}
}
// 0, 0 또는 최댓값, 최솟값 반환
return answer;
}
}
풀이 2
앞선 풀이에서 set.contains()의 시간 복잡도가 O(1)이므로 공통된 수들을 담는 set을 사용했는데, 상황에 따라 비효율적일 수 있다는 생각이 들었다. 예를 들어 최소 힙에서 뺀 여러 개의 값이 최대 힙의 최댓값으로 존재하여, 최대 힙에서 값을 빼는데 최악의 경우 O(N)만큼의 시간이 걸릴 수 있기 때문이다. 따라서 다음과 같이 최소 힙과 최대 힙을 사용한 풀이도 참고하자. 참고로 다음 풀이에서 사용한 우선순위 큐의 remove() 메소드는 O(N)의 시간 복잡도를 갖는다.
import java.util.*;
class Solution {
public int[] solution(String[] operations) {
Queue<Integer> maxQue = new PriorityQueue<>((o1, o2) -> o2 - o1);
Queue<Integer> minQue = new PriorityQueue<>();
for (String s : operations) {
String op = s.split(" ")[0];
int num = Integer.parseInt(s.split(" ")[1]);
if (op.equals("I")) {
maxQue.add(num);
minQue.add(num);
}
if (op.equals("D") && num == 1) {
if (maxQue.isEmpty()) continue;
minQue.remove(maxQue.poll());
}
if (op.equals("D") && num == -1) {
if (minQue.isEmpty()) continue;
maxQue.remove(minQue.poll());
}
}
int[] answer = new int[2];
if (maxQue.size() == 0) {
return answer;
}
answer[0] = maxQue.poll();
answer[1] = minQue.poll();
return answer;
}
}
시간 복잡도 비교
풀이 1과 풀이 2의 시간 복잡도를 비교해보자.
- 풀이 1
- operations의 길이 (M)
- operation 처리 (N * logN)
- 우선순위 큐에 add (logN) + set에 값을 넣기 (1)
- while 문을 돌며 poll (최악의 경우 N) * ( 우선순위 큐에서 poll (logN) + set.contains()와 set.remove() (1) )
- ➡️ O(M * N * logN)
- 풀이 2
- operations의 길이 (M)
- operation 처리 (N)
- 우선순위 큐에 add (logN)
- 우선순위 큐에서 poll (logN), 우선순위 큐에서 remove (N)
- ➡️ O(M * N)
무작정 풀이 1을 떠올리고 set.contains()가 O(1)의 시간 복잡도이므로 효율적일 것이라고 생각했는데, 최악의 경우까지 고려해서 시간 복잡도를 생각했어야 했다. 다음에는 여러 방법을 떠올려 보고 시간 복잡도를 비교한 후에 최적의 풀이로 풀어보자.
'CS > Algorism' 카테고리의 다른 글
99클럽 코테 스터디 8일차 TIL: [LeetCode] 899. Orderly Queue (0) | 2024.05.27 |
---|---|
99클럽 코테 스터디 7일차 TIL: [LeetCode] 2551. Put Marbles in Bags (0) | 2024.05.26 |
99클럽 코테 스터디 5일차 TIL: [프로그래머스] 디스크 컨트롤러 (0) | 2024.05.24 |
99클럽 코테 스터디 4일차 TIL: [프로그래머스] 주식가격 (0) | 2024.05.23 |
[백준] 12865. 평범한 배낭 (0) | 2024.05.23 |