key
(참가자 이름)을 찾는다.Q. 🧐 해시맵에서 값으로 조회하는 것은 비효율적이지 않을까?
A. 마지막 4번에서 완주하지 못한 참가자를 찾는데 최악의 경우 O(N)이 걸리게 된다. 완주하지 못한 참가자는 단 한명이므로, 해시 맵을 순회하며 0이 아닌 첫 번째 값을 찾으면 즉시 순회를 중단할 수 있어 실행시간은 빠른 편이다. (특히 내가 먼저 구현했던 ArrayList를 이용한 것에 비하면...)
import java.util.*;
class Solution {
public String solution(String[] participant, String[] completion) {
HashMap<String, Integer> participants = new HashMap<String, Integer>();
// 참가자 명단을 해시맵에 추가
for (String player : participant) {
participants.put(player, participants.getOrDefault(player, 0) + 1);
}
// 완주자 명단을 통해 참가자 명단에서 제거
for (String player : completion) {
participants.put(player, participants.get(player) - 1);
}
// 해시맵에서 값이 0이 아닌 참가자를 찾음
for (String player : participants.keySet()) {
if (participants.get(player) == 1) {
return player;
}
}
// 이론상 도달하지 않음
return null;
}
}
put
), 조회(get
), 값 갱신은 평균적으로 O(1)의 시간 복잡도를 가진다. 해시 충돌이 발생하지 않는 이상, 이러한 연산은 매우 빠르다.put
)하는 작업: 각 참가자마다 평균 O(1)put
to update)하는 작업: 각 완주자마다 평균 O(1)내가 처음 아무 생각없이 ArrayList
를 사용해서 작성한 코드다. 시간소요에서 문제를 통과하지 못했다.
ArrayList
에서 특정 요소를 찾는 작업(contains
)과 요소를 제거하는 작업(remove
)은 리스트의 크기에 비례하는 시간이 걸린다.import java.util.*;
class Solution {
public String solution(String[] participant, String[] completion) {
String answer = "";
List<String> strList = new ArrayList<>(Arrays.asList(participant));
for (String str : completion) {
if(strList.contains(str)) {
strList.remove(str);
}
}
return strList.get(0);
}
}
contains(str)
remove(str)
contains
와 remove
를 호출할 때마다 O(N)의 시간이 소요되기 때문