## 🌟 문제
[코딩테스트 연습 - 완주하지 못한 선수 \| 프로그래머스 스쿨](https://school.programmers.co.kr/learn/courses/30/lessons/42576)
마라톤에 참여한 선수들의 이름이 담긴 배열 participant와 완주한 선수들의 이름이 담긴 배열 completion이 주어질 때, 완주하지 못한 선수의 이름을 구하는 문제.
## 🌟 풀이
동명이인이 있을 수 있기 때문에 각 이름의 등장 횟수도 함께 세어줘야 했다. Map을 이용해서 이름의 등장 횟수와 이름을 매핑해주었다.
재밌었던 것은 이 문제를 2개월 전에 풀었을 때에는 completion을 기준으로 Map을 만들어서 풀었었는데, 이번에 풀 때에는 participant를 기준으로 Map을 만들어서 풀었다는 점이었다.
### completion을 기준으로 Map 만들기
"완주자 명단을 먼저 만들어두고, 참가자를 하나씩 대조하면서 명단에 없는 사람을 찾자."
- completion을 순회하면서 Map에 완주자 정보를 저장하고
- participant를 순회하면서 Map에 없거나 카운트가 0인 사람 찾기
```javascript
function solution1(participant, completion) {
// 1. completion으로 map 만들기
const map = new Map();
for (const person of completion) {
if (map.has(person)) {
map.set(person, map.get(person) + 1);
} else {
map.set(person, 1);
}
}
// 2. participant 돌면서 map에 없는 사람 찾기
for (const person of participant) {
if (!map.has(person) || map.get(person) === 0) {
return person;
} else {
map.set(person, map.get(person) - 1);
}
}
return ""; // 모든 사람이 완주했을 경우 (문제 조건상 발생하지 않음)
}
```
### participant를 기준으로 Map 만들기
"전체 참가자를 먼저 세어두고, 완주한 사람을 하나씩 지웠을 때 남은 한 사람이 미완주자"
- participant를 순회하며 Map에 참가자 정보 저장
- completion을 순회하며 완주한 사람의 카운트 감소
- Map을 순회하며 카운트가 0보다 큰 사람 찾기
```javascript
function solution2(participant, completion) {
// 참여자 맵 초기화
const participantMap = new Map(); // key: 이름, value: 해당하는 선수 수
for (const name of participant) {
if (participantMap.has(name)) {
participantMap.set(name, participantMap.get(name) + 1);
} else {
participantMap.set(name, 1);
}
}
// 완주자 확인
for (const name of completion) {
participantMap.set(name, participantMap.get(name) - 1);
}
// 완주하지 못한 선수 확인
for (const [name, count] of participantMap) {
if (count > 0) return name;
}
return ""; // NEVER
}
```
### 비교?
completion 기준으로 Map을 만드는 방법과 participant 기준으로 Map을 만드는 방법의 가장 큰 차이는 언제 판단해서 반환하느냐에 있는 것 같다.
- completion 기준: participant를 순회하는 중간에 바로 찾아서 반환
- participant 기준: 모든 데이터를 처리한 후에 결과를 찾음
비록 for문의 개수 차이가 있긴 하지만 worse case를 기준으로 하더라도 둘 다 시간복잡도가 O(N)이기 때문에 성능상 차이는 크게 없을 것 같다...!